diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /extensions/spellcheck/hunspell | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'extensions/spellcheck/hunspell')
614 files changed, 30726 insertions, 0 deletions
diff --git a/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl b/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl new file mode 100644 index 000000000..7fd918364 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PContent; + +namespace mozilla { + +sync protocol PRemoteSpellcheckEngine { + manager PContent; + +parent: + async __delete__(); + + sync Check(nsString aWord) returns (bool aIsMisspelled); + + sync CheckAndSuggest(nsString aWord) returns (bool aIsMisspelled, nsString[] aSuggestions); + + sync SetDictionary(nsString aDictionary) returns (bool success); +}; + +} // namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp new file mode 100644 index 000000000..dadfb2963 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoteSpellCheckEngineChild.h" + +namespace mozilla { + +RemoteSpellcheckEngineChild::RemoteSpellcheckEngineChild(mozSpellChecker *aOwner) + : mOwner(aOwner) +{ +} + +RemoteSpellcheckEngineChild::~RemoteSpellcheckEngineChild() +{ + // null out the owner's SpellcheckEngineChild to prevent state corruption + // during shutdown + mOwner->DeleteRemoteEngine(); +} + +} //namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h new file mode 100644 index 000000000..2cc40ce1f --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RemoteSpellcheckEngineChild_h_ +#define RemoteSpellcheckEngineChild_h_ + +#include "mozilla/PRemoteSpellcheckEngineChild.h" +#include "mozSpellChecker.h" + +class mozSpellChecker; + +namespace mozilla { + +class RemoteSpellcheckEngineChild : public mozilla::PRemoteSpellcheckEngineChild +{ +public: + explicit RemoteSpellcheckEngineChild(mozSpellChecker *aOwner); + virtual ~RemoteSpellcheckEngineChild(); + +private: + mozSpellChecker *mOwner; +}; + +} //namespace mozilla + +#endif // RemoteSpellcheckEngineChild_h_ diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp new file mode 100644 index 000000000..ce20b4e19 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp @@ -0,0 +1,63 @@ +/* vim: set ts=2 sw=2 sts=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoteSpellCheckEngineParent.h" +#include "nsISpellChecker.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { + +RemoteSpellcheckEngineParent::RemoteSpellcheckEngineParent() +{ + mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID); +} + +RemoteSpellcheckEngineParent::~RemoteSpellcheckEngineParent() +{ +} + +bool +RemoteSpellcheckEngineParent::RecvSetDictionary( + const nsString& aDictionary, + bool* success) +{ + nsresult rv = mSpellChecker->SetCurrentDictionary(aDictionary); + *success = NS_SUCCEEDED(rv); + return true; +} + +bool +RemoteSpellcheckEngineParent::RecvCheck( + const nsString& aWord, + bool* aIsMisspelled) +{ + nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, nullptr); + + // If CheckWord failed, we can't tell whether the word is correctly spelled. + if (NS_FAILED(rv)) + *aIsMisspelled = false; + return true; +} + +bool +RemoteSpellcheckEngineParent::RecvCheckAndSuggest( + const nsString& aWord, + bool* aIsMisspelled, + InfallibleTArray<nsString>* aSuggestions) +{ + nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, aSuggestions); + if (NS_FAILED(rv)) { + aSuggestions->Clear(); + *aIsMisspelled = false; + } + return true; +} + +void +RemoteSpellcheckEngineParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // namespace mozilla diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h new file mode 100644 index 000000000..c0bb51139 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef RemoteSpellcheckEngineParent_h_ +#define RemoteSpellcheckEngineParent_h_ + +#include "mozilla/PRemoteSpellcheckEngineParent.h" +#include "nsCOMPtr.h" + +class nsISpellChecker; + +namespace mozilla { + +class RemoteSpellcheckEngineParent : public PRemoteSpellcheckEngineParent +{ +public: + RemoteSpellcheckEngineParent(); + + virtual ~RemoteSpellcheckEngineParent(); + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + virtual bool RecvSetDictionary(const nsString& aDictionary, + bool* success) override; + + virtual bool RecvCheck(const nsString& aWord, bool* aIsMisspelled) override; + + virtual bool RecvCheckAndSuggest(const nsString& aWord, + bool* aIsMisspelled, + InfallibleTArray<nsString>* aSuggestions) + override; + +private: + nsCOMPtr<nsISpellChecker> mSpellChecker; +}; + +} // namespace mozilla + +#endif diff --git a/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h b/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h new file mode 100644 index 000000000..729e66b8e --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h @@ -0,0 +1,58 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developers + * are Copyright (C) 2011 the Initial Developers. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef alloc_hooks_h__ +#define alloc_hooks_h__ + +/** + * This file is force-included in hunspell code. Its purpose is to add memory + * reporting to hunspell without modifying its code, in order to ease future + * upgrades. + * + * This file is force-included through mozilla-config.h which is generated + * during the configure step. + * + * Currently, the memory allocated using operator new/new[] is not being + * tracked, but that's OK, since almost all of the memory used by Hunspell is + * allocated using C memory allocation functions. + */ + +#include "mozilla/mozalloc.h" +#include "mozHunspellAllocator.h" + +#define malloc(size) HunspellAllocator::CountingMalloc(size) +#define calloc(count, size) HunspellAllocator::CountingCalloc(count, size) +#define free(ptr) HunspellAllocator::CountingFree(ptr) +#define realloc(ptr, size) HunspellAllocator::CountingRealloc(ptr, size) + +#endif diff --git a/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h b/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h new file mode 100644 index 000000000..a841567b9 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef fopen_hooks_h__ +#define fopen_hooks_h__ + +/** + * This file is force-included in hunspell code. Its purpose is to add + * readahead to fopen() calls in hunspell without modifying its code, in order + * to ease future upgrades. + * + * This file is force-included through mozilla-config.h which is generated + * during the configure step. + */ + +#include "mozilla/FileUtils.h" +#include <stdio.h> +#include <string.h> + +#if defined(XP_WIN) +#include "nsNativeCharsetUtils.h" +#include "nsString.h" + +#include <fcntl.h> +#include <windows.h> +// Hunspell defines a function named near. Windef.h #defines near. +#undef near +// mozHunspell defines a function named RemoveDirectory. +#undef RemoveDirectory +#endif /* defined(XP_WIN) */ + +inline FILE* +hunspell_fopen_readahead(const char* filename, const char* mode) +{ + if (!filename || !mode) { + return nullptr; + } + // Fall back to libc's fopen for modes not supported by ReadAheadFile + if (!strchr(mode, 'r') || strchr(mode, '+')) { + return fopen(filename, mode); + } + int fd = -1; +#if defined(XP_WIN) + // filename is obtained via the nsIFile::nativePath attribute, so + // it is using the Windows ANSI code page, NOT UTF-8! + nsAutoString utf16Filename; + nsresult rv = NS_CopyNativeToUnicode(nsDependentCString(filename), + utf16Filename); + if (NS_FAILED(rv)) { + return nullptr; + } + HANDLE handle = INVALID_HANDLE_VALUE; + mozilla::ReadAheadFile(utf16Filename.get(), 0, SIZE_MAX, &handle); + if (handle == INVALID_HANDLE_VALUE) { + return nullptr; + } + int flags = _O_RDONLY; + // MSVC CRT's _open_osfhandle only supports adding _O_TEXT, not _O_BINARY + if (strchr(mode, 't')) { + // Force translated mode + flags |= _O_TEXT; + } + // Import the Win32 fd into the CRT + fd = _open_osfhandle((intptr_t)handle, flags); + if (fd < 0) { + CloseHandle(handle); + return nullptr; + } +#else + mozilla::ReadAheadFile(filename, 0, SIZE_MAX, &fd); + if (fd < 0) { + return nullptr; + } +#endif /* defined(XP_WIN) */ + + FILE* file = fdopen(fd, mode); + if (!file) { + close(fd); + } + return file; +} + +#define fopen(filename, mode) hunspell_fopen_readahead(filename, mode) + +#endif /* fopen_hooks_h__ */ + diff --git a/extensions/spellcheck/hunspell/glue/moz.build b/extensions/spellcheck/hunspell/glue/moz.build new file mode 100644 index 000000000..1e1d9711a --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/moz.build @@ -0,0 +1,39 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'mozHunspell.cpp', + 'mozHunspellDirProvider.cpp', + 'RemoteSpellCheckEngineChild.cpp', + 'RemoteSpellCheckEngineParent.cpp', +] + +FINAL_LIBRARY = 'xul' + +if CONFIG['MOZ_SYSTEM_HUNSPELL']: + CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS'] +else: + LOCAL_INCLUDES += ['../src'] + +LOCAL_INCLUDES += [ + '/dom/base', + '/extensions/spellcheck/src', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +IPDL_SOURCES = [ + 'PRemoteSpellcheckEngine.ipdl', +] + +EXPORTS.mozilla += [ + 'RemoteSpellCheckEngineChild.h', + 'RemoteSpellCheckEngineParent.h', +] + +# This variable is referenced in configure.in. Make sure to change that file +# too if you need to change this variable. +DEFINES['HUNSPELL_STATIC'] = True diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp new file mode 100644 index 000000000..87ffbc661 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp @@ -0,0 +1,623 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) + * David Einstein (deinst@world.std.com) + * Michiel van Leeuwen (mvl@exedo.nl) + * Caolan McNamara (cmc@openoffice.org) + * László Németh (nemethl@gyorsposta.hu) + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * Jesper Kristensen (mail@jesperkristensen.dk) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#include "mozHunspell.h" +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" +#include "nsIObserverService.h" +#include "nsISimpleEnumerator.h" +#include "nsIDirectoryEnumerator.h" +#include "nsIFile.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "mozISpellI18NManager.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicharUtils.h" +#include "nsCRT.h" +#include "mozInlineSpellChecker.h" +#include "mozilla/Services.h" +#include <stdlib.h> +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/ContentParent.h" + +using mozilla::dom::ContentParent; +using mozilla::dom::EncodingUtils; + +NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell) +NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell) + +NS_INTERFACE_MAP_BEGIN(mozHunspell) + NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine) + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION(mozHunspell, + mPersonalDictionary, + mEncoder, + mDecoder) + +template<> mozilla::Atomic<size_t> mozilla::CountingAllocatorBase<HunspellAllocator>::sAmount(0); + +mozHunspell::mozHunspell() + : mHunspell(nullptr) +{ +#ifdef DEBUG + // There must be only one instance of this class: it reports memory based on + // a single static count in HunspellAllocator. + static bool hasRun = false; + MOZ_ASSERT(!hasRun); + hasRun = true; +#endif +} + +nsresult +mozHunspell::Init() +{ + LoadDictionaryList(false); + + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, "profile-do-change", true); + obs->AddObserver(this, "profile-after-change", true); + } + + mozilla::RegisterWeakMemoryReporter(this); + + return NS_OK; +} + +mozHunspell::~mozHunspell() +{ + mozilla::UnregisterWeakMemoryReporter(this); + + mPersonalDictionary = nullptr; + delete mHunspell; +} + +NS_IMETHODIMP mozHunspell::GetDictionary(char16_t **aDictionary) +{ + NS_ENSURE_ARG_POINTER(aDictionary); + + *aDictionary = ToNewUnicode(mDictionary); + return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* set the Dictionary. + * This also Loads the dictionary and initializes the converter using the dictionaries converter + */ +NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) +{ + NS_ENSURE_ARG_POINTER(aDictionary); + + if (nsDependentString(aDictionary).IsEmpty()) { + delete mHunspell; + mHunspell = nullptr; + mDictionary.Truncate(); + mAffixFileName.Truncate(); + mLanguage.Truncate(); + mDecoder = nullptr; + mEncoder = nullptr; + + return NS_OK; + } + + nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary)); + if (!affFile) + return NS_ERROR_FILE_NOT_FOUND; + + nsAutoCString 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 nsIFile, and get a filehandle + // from there. Only problem is that hunspell wants a path + + nsresult rv = affFile->GetNativePath(affFileName); + NS_ENSURE_SUCCESS(rv, rv); + + if (mAffixFileName.Equals(affFileName.get())) + return NS_OK; + + dictFileName = affFileName; + int32_t 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 mHunspell instance which needs cleaned up. + delete mHunspell; + + mDictionary = aDictionary; + mAffixFileName = affFileName; + + mHunspell = new Hunspell(affFileName.get(), + dictFileName.get()); + if (!mHunspell) + return NS_ERROR_OUT_OF_MEMORY; + + nsDependentCString label(mHunspell->get_dic_encoding()); + nsAutoCString encoding; + if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { + return NS_ERROR_UCONV_NOCONV; + } + mEncoder = EncodingUtils::EncoderForEncoding(encoding); + mDecoder = EncodingUtils::DecoderForEncoding(encoding); + + if (mEncoder) + mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nullptr, '?'); + + int32_t pos = mDictionary.FindChar('-'); + if (pos == -1) + pos = mDictionary.FindChar('_'); + + if (pos == -1) + mLanguage.Assign(mDictionary); + else + mLanguage = Substring(mDictionary, 0, pos); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetLanguage(char16_t **aLanguage) +{ + NS_ENSURE_ARG_POINTER(aLanguage); + + if (mDictionary.IsEmpty()) + return NS_ERROR_NOT_INITIALIZED; + + *aLanguage = ToNewUnicode(mLanguage); + return *aLanguage ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP mozHunspell::GetProvidesPersonalDictionary(bool *aProvidesPersonalDictionary) +{ + NS_ENSURE_ARG_POINTER(aProvidesPersonalDictionary); + + *aProvidesPersonalDictionary = false; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetProvidesWordUtils(bool *aProvidesWordUtils) +{ + NS_ENSURE_ARG_POINTER(aProvidesWordUtils); + + *aProvidesWordUtils = false; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetName(char16_t * *aName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozHunspell::GetCopyright(char16_t * *aCopyright) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP mozHunspell::GetPersonalDictionary(mozIPersonalDictionary * *aPersonalDictionary) +{ + *aPersonalDictionary = mPersonalDictionary; + NS_IF_ADDREF(*aPersonalDictionary); + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::SetPersonalDictionary(mozIPersonalDictionary * aPersonalDictionary) +{ + mPersonalDictionary = aPersonalDictionary; + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries, + uint32_t *aCount) +{ + if (!aDictionaries || !aCount) + return NS_ERROR_NULL_POINTER; + + uint32_t count = 0; + char16_t** dicts = + (char16_t**) moz_xmalloc(sizeof(char16_t*) * mDictionaries.Count()); + + for (auto iter = mDictionaries.Iter(); !iter.Done(); iter.Next()) { + dicts[count] = ToNewUnicode(iter.Key()); + if (!dicts[count]) { + while (count) { + --count; + free(dicts[count]); + } + free(dicts); + return NS_ERROR_OUT_OF_MEMORY; + } + + ++count; + } + + *aDictionaries = dicts; + *aCount = count; + + return NS_OK; +} + +void +mozHunspell::LoadDictionaryList(bool aNotifyChildProcesses) +{ + mDictionaries.Clear(); + + nsresult rv; + + nsCOMPtr<nsIProperties> dirSvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if (!dirSvc) + return; + + // find built in dictionaries, or dictionaries specified in + // spellchecker.dictionary_path in prefs + nsCOMPtr<nsIFile> dictDir; + + // check preferences first + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + nsCString extDictPath; + rv = prefs->GetCharPref("spellchecker.dictionary_path", getter_Copies(extDictPath)); + if (NS_SUCCEEDED(rv)) { + // set the spellchecker.dictionary_path + rv = NS_NewNativeLocalFile(extDictPath, true, getter_AddRefs(dictDir)); + } + } + if (!dictDir) { + // spellcheck.dictionary_path not found, set internal path + rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY, + NS_GET_IID(nsIFile), getter_AddRefs(dictDir)); + } + if (dictDir) { + LoadDictionariesFromDir(dictDir); + } + else { + // try to load gredir/dictionaries + nsCOMPtr<nsIFile> greDir; + rv = dirSvc->Get(NS_GRE_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(greDir)); + if (NS_SUCCEEDED(rv)) { + greDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + LoadDictionariesFromDir(greDir); + } + + // try to load appdir/dictionaries only if different than gredir + nsCOMPtr<nsIFile> appDir; + rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(appDir)); + bool equals; + if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) { + appDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + LoadDictionariesFromDir(appDir); + } + } + + // find dictionaries in DICPATH + char* dicEnv = PR_GetEnv("DICPATH"); + if (dicEnv) { + // do a two-pass dance so dictionaries are loaded right-to-left as preference + nsTArray<nsCOMPtr<nsIFile>> dirs; + nsAutoCString env(dicEnv); // assume dicEnv is UTF-8 + + char* currPath = nullptr; + char* nextPaths = env.BeginWriting(); + while ((currPath = NS_strtok(":", &nextPaths))) { + nsCOMPtr<nsIFile> dir; + rv = NS_NewNativeLocalFile(nsCString(currPath), true, getter_AddRefs(dir)); + if (NS_SUCCEEDED(rv)) { + dirs.AppendElement(dir); + } + } + + // load them in reverse order so they override each other properly + for (int32_t i = dirs.Length() - 1; i >= 0; i--) { + LoadDictionariesFromDir(dirs[i]); + } + } + + // find dictionaries from extensions requiring restart + nsCOMPtr<nsISimpleEnumerator> dictDirs; + rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST, + NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dictDirs)); + if (NS_FAILED(rv)) + return; + + bool hasMore; + while (NS_SUCCEEDED(dictDirs->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> elem; + dictDirs->GetNext(getter_AddRefs(elem)); + + dictDir = do_QueryInterface(elem); + if (dictDir) + LoadDictionariesFromDir(dictDir); + } + + // find dictionaries from restartless extensions + for (int32_t i = 0; i < mDynamicDirectories.Count(); i++) { + LoadDictionariesFromDir(mDynamicDirectories[i]); + } + + // Now we have finished updating the list of dictionaries, update the current + // dictionary and any editors which may use it. + mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking(); + + if (aNotifyChildProcesses) { + ContentParent::NotifyUpdatedDictionaries(); + } + + // Check if the current dictionary is still available. + // If not, try to replace it with another dictionary of the same language. + if (!mDictionary.IsEmpty()) { + rv = SetDictionary(mDictionary.get()); + if (NS_SUCCEEDED(rv)) + return; + } + + // If the current dictionary has gone, and we don't have a good replacement, + // set no current dictionary. + if (!mDictionary.IsEmpty()) { + SetDictionary(EmptyString().get()); + } +} + +NS_IMETHODIMP +mozHunspell::LoadDictionariesFromDir(nsIFile* aDir) +{ + nsresult rv; + + bool check = false; + rv = aDir->Exists(&check); + if (NS_FAILED(rv) || !check) + return NS_ERROR_UNEXPECTED; + + rv = aDir->IsDirectory(&check); + if (NS_FAILED(rv) || !check) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsISimpleEnumerator> e; + rv = aDir->GetDirectoryEntries(getter_AddRefs(e)); + if (NS_FAILED(rv)) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e)); + if (!files) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr<nsIFile> file; + while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file) { + nsAutoString leafName; + file->GetLeafName(leafName); + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic"))) + continue; + + nsAutoString dict(leafName); + dict.SetLength(dict.Length() - 4); // magic length of ".dic" + + // check for the presence of the .aff file + leafName = dict; + leafName.AppendLiteral(".aff"); + file->SetLeafName(leafName); + rv = file->Exists(&check); + if (NS_FAILED(rv) || !check) + continue; + +#ifdef DEBUG_bsmedberg + printf("Adding dictionary: %s\n", NS_ConvertUTF16toUTF8(dict).get()); +#endif + + // Replace '_' separator with '-' + dict.ReplaceChar("_", '-'); + + mDictionaries.Put(dict, file); + } + + return NS_OK; +} + +nsresult mozHunspell::ConvertCharset(const char16_t* aStr, char ** aDst) +{ + NS_ENSURE_ARG_POINTER(aDst); + NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER); + + int32_t outLength; + int32_t inLength = NS_strlen(aStr); + nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength); + NS_ENSURE_SUCCESS(rv, rv); + + *aDst = (char *) moz_xmalloc(sizeof(char) * (outLength+1)); + NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY); + + rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength); + if (NS_SUCCEEDED(rv)) + (*aDst)[outLength] = '\0'; + + return rv; +} + +NS_IMETHODIMP +mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) +{ + MOZ_COLLECT_REPORT( + "explicit/spell-check", KIND_HEAP, UNITS_BYTES, + HunspellAllocator::MemoryAllocated(), + "Memory used by the spell-checking engine."); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::Check(const char16_t *aWord, bool *aResult) +{ + NS_ENSURE_ARG_POINTER(aWord); + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); + + nsXPIDLCString charsetWord; + nsresult rv = ConvertCharset(aWord, getter_Copies(charsetWord)); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = !!mHunspell->spell(charsetWord); + + + if (!*aResult && mPersonalDictionary) + rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult); + + return rv; +} + +NS_IMETHODIMP mozHunspell::Suggest(const char16_t *aWord, char16_t ***aSuggestions, uint32_t *aSuggestionCount) +{ + NS_ENSURE_ARG_POINTER(aSuggestions); + NS_ENSURE_ARG_POINTER(aSuggestionCount); + NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); + + nsresult rv; + *aSuggestionCount = 0; + + nsXPIDLCString charsetWord; + rv = ConvertCharset(aWord, getter_Copies(charsetWord)); + NS_ENSURE_SUCCESS(rv, rv); + + char ** wlst; + *aSuggestionCount = mHunspell->suggest(&wlst, charsetWord); + + if (*aSuggestionCount) { + *aSuggestions = (char16_t **)moz_xmalloc(*aSuggestionCount * sizeof(char16_t *)); + if (*aSuggestions) { + uint32_t index = 0; + for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) { + // Convert the suggestion to utf16 + int32_t inLength = strlen(wlst[index]); + int32_t outLength; + rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength); + if (NS_SUCCEEDED(rv)) + { + (*aSuggestions)[index] = (char16_t *) moz_xmalloc(sizeof(char16_t) * (outLength+1)); + if ((*aSuggestions)[index]) + { + rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength); + if (NS_SUCCEEDED(rv)) + (*aSuggestions)[index][outLength] = 0; + } + else + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + if (NS_FAILED(rv)) + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the char16_t strings up to the point at which the error occurred + } + else // if (*aSuggestions) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst); + return rv; +} + +NS_IMETHODIMP +mozHunspell::Observe(nsISupports* aSubj, const char *aTopic, + const char16_t *aData) +{ + NS_ASSERTION(!strcmp(aTopic, "profile-do-change") + || !strcmp(aTopic, "profile-after-change"), + "Unexpected observer topic"); + + LoadDictionaryList(false); + + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir) +{ + mDynamicDirectories.AppendObject(aDir); + LoadDictionaryList(true); + return NS_OK; +} + +NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir) +{ + mDynamicDirectories.RemoveObject(aDir); + LoadDictionaryList(true); + +#ifdef MOZ_THUNDERBIRD + /* + * This notification is needed for Thunderbird. Thunderbird derives the dictionary + * from the document's "lang" attribute. If a dictionary is removed, + * we need to change the "lang" attribute. + */ + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, + SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION, + nullptr); + } +#endif + return NS_OK; +} diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.h b/extensions/spellcheck/hunspell/glue/mozHunspell.h new file mode 100644 index 000000000..01ef741aa --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspell.h @@ -0,0 +1,125 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) + * David Einstein (deinst@world.std.com) + * Michiel van Leeuwen (mvl@exedo.nl) + * Caolan McNamara (cmc@openoffice.org) + * László Németh (nemethl@gyorsposta.hu) + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * Jesper Kristensen (mail@jesperkristensen.dk) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef mozHunspell_h__ +#define mozHunspell_h__ + +#include <hunspell.hxx> +#include "mozISpellCheckingEngine.h" +#include "mozIPersonalDictionary.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIMemoryReporter.h" +#include "nsIObserver.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "nsInterfaceHashtable.h" +#include "nsWeakReference.h" +#include "nsCycleCollectionParticipant.h" +#include "mozHunspellAllocator.h" + +#define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1" +#define MOZ_HUNSPELL_CID \ +/* 56c778e4-1bee-45f3-a689-886692a97fe7 */ \ +{ 0x56c778e4, 0x1bee, 0x45f3, \ + { 0xa6, 0x89, 0x88, 0x66, 0x92, 0xa9, 0x7f, 0xe7 } } + +class mozHunspell final : public mozISpellCheckingEngine, + public nsIObserver, + public nsSupportsWeakReference, + public nsIMemoryReporter +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_MOZISPELLCHECKINGENGINE + NS_DECL_NSIOBSERVER + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozHunspell, mozISpellCheckingEngine) + + mozHunspell(); + + nsresult Init(); + + void LoadDictionaryList(bool aNotifyChildProcesses); + + // helper method for converting a word to the charset of the dictionary + nsresult ConvertCharset(const char16_t* aStr, char ** aDst); + + NS_DECL_NSIMEMORYREPORTER + +protected: + virtual ~mozHunspell(); + + nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary; + nsCOMPtr<nsIUnicodeEncoder> mEncoder; + nsCOMPtr<nsIUnicodeDecoder> mDecoder; + + // Hashtable matches dictionary name to .aff file + nsInterfaceHashtable<nsStringHashKey, nsIFile> mDictionaries; + nsString mDictionary; + nsString mLanguage; + nsCString mAffixFileName; + + // dynamic dirs used to search for dictionaries + nsCOMArray<nsIFile> mDynamicDirectories; + + Hunspell *mHunspell; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h b/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h new file mode 100644 index 000000000..219d4a5dd --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozHunspellAllocator_h__ +#define mozHunspellAllocator_h__ + +#include "mozilla/CountingAllocatorBase.h" + +class HunspellAllocator : public mozilla::CountingAllocatorBase<HunspellAllocator> +{ +}; + +#endif diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp new file mode 100644 index 000000000..00758b0c3 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp @@ -0,0 +1,140 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Benjamin Smedberg (benjamin@smedbergs.us) (Original Code) + * László Németh (nemethl@gyorsposta.hu) + * Ryan VanderMeulen (ryanvm@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#include "mozHunspellDirProvider.h" +#include "nsXULAppAPI.h" +#include "nsString.h" + +#include "mozISpellCheckingEngine.h" +#include "nsICategoryManager.h" + +NS_IMPL_ISUPPORTS(mozHunspellDirProvider, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + +NS_IMETHODIMP +mozHunspellDirProvider::GetFile(const char *aKey, bool *aPersist, + nsIFile* *aResult) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +mozHunspellDirProvider::GetFiles(const char *aKey, + nsISimpleEnumerator* *aResult) +{ + if (strcmp(aKey, DICTIONARY_SEARCH_DIRECTORY_LIST) != 0) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIProperties> dirSvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if (!dirSvc) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsISimpleEnumerator> list; + nsresult rv = dirSvc->Get(XRE_EXTENSIONS_DIR_LIST, + NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(list)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsISimpleEnumerator> e = new AppendingEnumerator(list); + if (!e) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = nullptr; + e.swap(*aResult); + return NS_SUCCESS_AGGREGATE_RESULT; +} + +NS_IMPL_ISUPPORTS(mozHunspellDirProvider::AppendingEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +mozHunspellDirProvider::AppendingEnumerator::HasMoreElements(bool *aResult) +{ + *aResult = mNext ? true : false; + return NS_OK; +} + +NS_IMETHODIMP +mozHunspellDirProvider::AppendingEnumerator::GetNext(nsISupports* *aResult) +{ + if (aResult) + NS_ADDREF(*aResult = mNext); + + mNext = nullptr; + + nsresult rv; + + // Ignore all errors + + bool more; + while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) { + nsCOMPtr<nsISupports> nextbasesupp; + mBase->GetNext(getter_AddRefs(nextbasesupp)); + + nsCOMPtr<nsIFile> nextbase(do_QueryInterface(nextbasesupp)); + if (!nextbase) + continue; + + nextbase->Clone(getter_AddRefs(mNext)); + if (!mNext) + continue; + + mNext->AppendNative(NS_LITERAL_CSTRING("dictionaries")); + + bool exists; + rv = mNext->Exists(&exists); + if (NS_SUCCEEDED(rv) && exists) + break; + + mNext = nullptr; + } + + return NS_OK; +} + +mozHunspellDirProvider::AppendingEnumerator::AppendingEnumerator + (nsISimpleEnumerator* aBase) : + mBase(aBase) +{ + // Initialize mNext to begin + GetNext(nullptr); +} + +char const *const +mozHunspellDirProvider::kContractID = "@mozilla.org/spellcheck/dir-provider;1"; diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h new file mode 100644 index 000000000..60ab23be8 --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h @@ -0,0 +1,77 @@ +/******* BEGIN LICENSE BLOCK ******* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) + * and László Németh (Hunspell). Portions created by the Initial Developers + * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. + * + * Contributor(s): Benjamin Smedberg (benjamin@smedbergs.us) (Original Code) + * László Németh (nemethl@gyorsposta.hu) + * Ryan VanderMeulen (ryanvm@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + ******* END LICENSE BLOCK *******/ + +#ifndef mozHunspellDirProvider_h__ +#define mozHunspellDirProvider_h__ + +#include "nsIDirectoryService.h" +#include "nsIFile.h" +#include "nsISimpleEnumerator.h" +#include "mozilla/Attributes.h" + +class mozHunspellDirProvider final : + public nsIDirectoryServiceProvider2 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + + static char const *const kContractID; + +private: + ~mozHunspellDirProvider() {} + + class AppendingEnumerator final : public nsISimpleEnumerator + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + explicit AppendingEnumerator(nsISimpleEnumerator* aBase); + + private: + ~AppendingEnumerator() {} + + nsCOMPtr<nsISimpleEnumerator> mBase; + nsCOMPtr<nsIFile> mNext; + }; +}; + +#define HUNSPELLDIRPROVIDER_CID \ +{ 0x64d6174c, 0x1496, 0x4ffd, \ + { 0x87, 0xf2, 0xda, 0x26, 0x70, 0xf8, 0x89, 0x34 } } + +#endif // mozHunspellDirProvider diff --git a/extensions/spellcheck/hunspell/moz.build b/extensions/spellcheck/hunspell/moz.build new file mode 100644 index 000000000..61955e506 --- /dev/null +++ b/extensions/spellcheck/hunspell/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['glue'] +if not CONFIG['MOZ_SYSTEM_HUNSPELL']: + DIRS += ['src'] + +if CONFIG['ENABLE_TESTS']: + XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] diff --git a/extensions/spellcheck/hunspell/src/README b/extensions/spellcheck/hunspell/src/README new file mode 100644 index 000000000..b97a112fd --- /dev/null +++ b/extensions/spellcheck/hunspell/src/README @@ -0,0 +1,21 @@ +Hunspell spell checker and morphological analyser library + +Documentation, tests, examples: http://hunspell.github.io/ + +Author of Hunspell: +László Németh (nemethl (at) gyorsposta.hu) + +Hunspell based on OpenOffice.org's Myspell. MySpell's author: +Kevin Hendricks (kevin.hendricks (at) sympatico.ca) + +License: GPL 2.0/LGPL 2.1/MPL 1.1 tri-license + +The contents of this library may be used under the terms of +the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL", +see http://gnu.org/copyleft/lesser.html) or the Mozilla Public License +Version 1.1 or later (the "MPL", see http://mozilla.org/MPL/MPL-1.1.html). + +Software distributed under these licenses is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the licences +for the specific language governing rights and limitations under the licenses. diff --git a/extensions/spellcheck/hunspell/src/README.mozilla b/extensions/spellcheck/hunspell/src/README.mozilla new file mode 100644 index 000000000..79a9f54d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/README.mozilla @@ -0,0 +1,2 @@ +Hunspell Version: 1.4.1 +Additional Patches: See patches directory. diff --git a/extensions/spellcheck/hunspell/src/affentry.cxx b/extensions/spellcheck/hunspell/src/affentry.cxx new file mode 100644 index 000000000..bd2827436 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affentry.cxx @@ -0,0 +1,1068 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "affentry.hxx" +#include "csutil.hxx" + +PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp) + // register affix manager + : pmyMgr(pmgr), + next(NULL), + nexteq(NULL), + nextne(NULL), + flgnxt(NULL) { + // set up its initial values + aflag = dp->aflag; // flag + strip = dp->strip; // string to strip + appnd = dp->appnd; // string to append + numconds = dp->numconds; // length of the condition + opts = dp->opts; // cross product flag + // then copy over all of the conditions + if (opts & aeLONGCOND) { + memcpy(c.conds, dp->c.l.conds1, MAXCONDLEN_1); + c.l.conds2 = dp->c.l.conds2; + } else + memcpy(c.conds, dp->c.conds, MAXCONDLEN); + morphcode = dp->morphcode; + contclass = dp->contclass; + contclasslen = dp->contclasslen; +} + +PfxEntry::~PfxEntry() { + aflag = 0; + pmyMgr = NULL; + if (opts & aeLONGCOND) + free(c.l.conds2); + if (morphcode && !(opts & aeALIASM)) + free(morphcode); + if (contclass && !(opts & aeALIASF)) + free(contclass); +} + +// add prefix to this word assuming conditions hold +char* PfxEntry::add(const char* word, size_t len) { + if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && + (len >= numconds) && test_condition(word) && + (!strip.size() || (strncmp(word, strip.c_str(), strip.size()) == 0))) { + /* we have a match so add prefix */ + std::string tword(appnd); + tword.append(word + strip.size()); + return mystrdup(tword.c_str()); + } + return NULL; +} + +inline char* PfxEntry::nextchar(char* p) { + if (p) { + p++; + if (opts & aeLONGCOND) { + // jump to the 2nd part of the condition + if (p == c.conds + MAXCONDLEN_1) + return c.l.conds2; + // end of the MAXCONDLEN length condition + } else if (p == c.conds + MAXCONDLEN) + return NULL; + return *p ? p : NULL; + } + return NULL; +} + +inline int PfxEntry::test_condition(const char* st) { + const char* pos = NULL; // group with pos input position + bool neg = false; // complementer + bool ingroup = false; // character in the group + if (numconds == 0) + return 1; + char* p = c.conds; + while (1) { + switch (*p) { + case '\0': + return 1; + case '[': { + neg = false; + ingroup = false; + p = nextchar(p); + pos = st; + break; + } + case '^': { + p = nextchar(p); + neg = true; + break; + } + case ']': { + if ((neg && ingroup) || (!neg && !ingroup)) + return 0; + pos = NULL; + p = nextchar(p); + // skip the next character + if (!ingroup && *st) + for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) + ; + if (*st == '\0' && p) + return 0; // word <= condition + break; + } + case '.': + if (!pos) { // dots are not metacharacters in groups: [.] + p = nextchar(p); + // skip the next character + for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++) + ; + if (*st == '\0' && p) + return 0; // word <= condition + break; + } + /* FALLTHROUGH */ + default: { + if (*st == *p) { + st++; + p = nextchar(p); + if ((opts & aeUTF8) && (*(st - 1) & 0x80)) { // multibyte + while (p && (*p & 0xc0) == 0x80) { // character + if (*p != *st) { + if (!pos) + return 0; + st = pos; + break; + } + p = nextchar(p); + st++; + } + if (pos && st != pos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + } + } else if (pos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + } + } else if (pos) { // group + p = nextchar(p); + } else + return 0; + } + } + if (!p) + return 1; + } +} + +// check if this prefix entry matches +struct hentry* PfxEntry::checkword(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if (tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { + do { + if (TESTAFF(he->astr, aflag, he->alen) && + // forbid single prefixes with needaffix flag + !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && + // needflag + ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || + (contclass && TESTAFF(contclass, needflag, contclasslen)))) + return he; + he = he->next_homonym; // check homonyms + } while (he); + } + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + // if ((opts & aeXPRODUCT) && in_compound) { + if ((opts & aeXPRODUCT)) { + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, aeXPRODUCT, this, + NULL, 0, NULL, FLAG_NULL, needflag, + in_compound); + if (he) + return he; + } + } + } + return NULL; +} + +// check if this prefix entry matches +struct hentry* PfxEntry::check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // cross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this, + needflag); + if (he) + return he; + } + } + } + return NULL; +} + +// check if this prefix entry matches +char* PfxEntry::check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + tmpl += strip.size(); + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + return pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl, + aeXPRODUCT, + this, needflag); + } + } + } + return NULL; +} + +// check if this prefix entry matches +char* PfxEntry::check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* he; // hash entry of root word or NULL + char* st; + + // on entry prefix is 0 length or already matches the beginning of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing prefix and adding + // back any characters that would have been stripped + + std::string tmpword(strip); + tmpword.append(word + appnd.size()); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(tmpword.c_str())) { + std::string result; + + tmpl += strip.size(); + if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) { + do { + if (TESTAFF(he->astr, aflag, he->alen) && + // forbid single prefixes with needaffix flag + !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) && + // needflag + ((!needflag) || TESTAFF(he->astr, needflag, he->alen) || + (contclass && TESTAFF(contclass, needflag, contclasslen)))) { + if (morphcode) { + result.append(" "); + result.append(morphcode); + } else + result.append(getKey()); + if (!HENTRY_FIND(he, MORPH_STEM)) { + result.append(" "); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(he)); + } + // store the pointer of the hash entry + if (HENTRY_DATA(he)) { + result.append(" "); + result.append(HENTRY_DATA2(he)); + } else { + // return with debug information + char* flag = pmyMgr->encode_flag(getFlag()); + result.append(" "); + result.append(MORPH_FLAG); + result.append(flag); + free(flag); + } + result.append("\n"); + } + he = he->next_homonym; + } while (he); + } + + // prefix matched but no root word was found + // if aeXPRODUCT is allowed, try again but now + // ross checked combined with a suffix + + if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this, + FLAG_NULL, needflag); + if (st) { + result.append(st); + free(st); + } + } + + if (!result.empty()) + return mystrdup(result.c_str()); + } + } + + return NULL; +} + +SfxEntry::SfxEntry(AffixMgr* pmgr, affentry* dp) + : pmyMgr(pmgr) // register affix manager + , + next(NULL), + nexteq(NULL), + nextne(NULL), + flgnxt(NULL), + l_morph(NULL), + r_morph(NULL), + eq_morph(NULL) { + // set up its initial values + aflag = dp->aflag; // char flag + strip = dp->strip; // string to strip + appnd = dp->appnd; // string to append + numconds = dp->numconds; // length of the condition + opts = dp->opts; // cross product flag + + // then copy over all of the conditions + if (opts & aeLONGCOND) { + memcpy(c.l.conds1, dp->c.l.conds1, MAXCONDLEN_1); + c.l.conds2 = dp->c.l.conds2; + } else + memcpy(c.conds, dp->c.conds, MAXCONDLEN); + rappnd = appnd; + reverseword(rappnd); + morphcode = dp->morphcode; + contclass = dp->contclass; + contclasslen = dp->contclasslen; +} + +SfxEntry::~SfxEntry() { + aflag = 0; + pmyMgr = NULL; + if (opts & aeLONGCOND) + free(c.l.conds2); + if (morphcode && !(opts & aeALIASM)) + free(morphcode); + if (contclass && !(opts & aeALIASF)) + free(contclass); +} + +// add suffix to this word assuming conditions hold +char* SfxEntry::add(const char* word, size_t len) { + /* make sure all conditions match */ + if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) && + (len >= numconds) && test_condition(word + len, word) && + (!strip.size() || + (strcmp(word + len - strip.size(), strip.c_str()) == 0))) { + std::string tword(word); + /* we have a match so add suffix */ + tword.replace(len - strip.size(), std::string::npos, appnd); + return mystrdup(tword.c_str()); + } + return NULL; +} + +inline char* SfxEntry::nextchar(char* p) { + if (p) { + p++; + if (opts & aeLONGCOND) { + // jump to the 2nd part of the condition + if (p == c.l.conds1 + MAXCONDLEN_1) + return c.l.conds2; + // end of the MAXCONDLEN length condition + } else if (p == c.conds + MAXCONDLEN) + return NULL; + return *p ? p : NULL; + } + return NULL; +} + +inline int SfxEntry::test_condition(const char* st, const char* beg) { + const char* pos = NULL; // group with pos input position + bool neg = false; // complementer + bool ingroup = false; // character in the group + if (numconds == 0) + return 1; + char* p = c.conds; + st--; + int i = 1; + while (1) { + switch (*p) { + case '\0': + return 1; + case '[': + p = nextchar(p); + pos = st; + break; + case '^': + p = nextchar(p); + neg = true; + break; + case ']': + if (!neg && !ingroup) + return 0; + i++; + // skip the next character + if (!ingroup) { + for (; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--) + ; + st--; + } + pos = NULL; + neg = false; + ingroup = false; + p = nextchar(p); + if (st < beg && p) + return 0; // word <= condition + break; + case '.': + if (!pos) { + // dots are not metacharacters in groups: [.] + p = nextchar(p); + // skip the next character + for (st--; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; + st--) + ; + if (st < beg) { // word <= condition + if (p) + return 0; + else + return 1; + } + if ((opts & aeUTF8) && (*st & 0x80)) { // head of the UTF-8 character + st--; + if (st < beg) { // word <= condition + if (p) + return 0; + else + return 1; + } + } + break; + } + /* FALLTHROUGH */ + default: { + if (*st == *p) { + p = nextchar(p); + if ((opts & aeUTF8) && (*st & 0x80)) { + st--; + while (p && (st >= beg)) { + if (*p != *st) { + if (!pos) + return 0; + st = pos; + break; + } + // first byte of the UTF-8 multibyte character + if ((*p & 0xc0) != 0x80) + break; + p = nextchar(p); + st--; + } + if (pos && st != pos) { + if (neg) + return 0; + else if (i == numconds) + return 1; + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + st--; + } + if (p && *p != ']') + p = nextchar(p); + } else if (pos) { + if (neg) + return 0; + else if (i == numconds) + return 1; + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != NULL)) { + } + // if (p && *p != ']') p = nextchar(p); + st--; + } + if (!pos) { + i++; + st--; + } + if (st < beg && p && *p != ']') + return 0; // word <= condition + } else if (pos) { // group + p = nextchar(p); + } else + return 0; + } + } + if (!p) + return 1; + } +} + +// see if this suffix is present in the word +struct hentry* SfxEntry::checkword(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass, + const FLAG needflag, + const FLAG badflag) { + struct hentry* he; // hash entry pointer + PfxEntry* ep = ppfx; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if (((optflags & aeXPRODUCT) != 0) && ((opts & aeXPRODUCT) == 0)) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + // the second condition is not enough for UTF-8 strings + // it checked in test_condition() + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpstring(word, tmpl); + if (strip.size()) { + tmpstring.append(strip); + } + + const char* tmpword = tmpstring.c_str(); + const char* endword = tmpword + tmpstring.size(); + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then check if resulting + // root word in the dictionary + + if (test_condition(endword, tmpword)) { +#ifdef SZOSZABLYA_POSSIBLE_ROOTS + fprintf(stdout, "%s %s %c\n", word, tmpword, aflag); +#endif + if ((he = pmyMgr->lookup(tmpword)) != NULL) { + do { + // check conditional suffix (enabled by prefix) + if ((TESTAFF(he->astr, aflag, he->alen) || + (ep && ep->getCont() && + TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && + (((optflags & aeXPRODUCT) == 0) || + (ep && TESTAFF(he->astr, ep->getFlag(), he->alen)) || + // enabled by prefix + ((contclass) && + (ep && TESTAFF(contclass, ep->getFlag(), contclasslen)))) && + // handle cont. class + ((!cclass) || + ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && + // check only in compound homonyms (bad flags) + (!badflag || !TESTAFF(he->astr, badflag, he->alen)) && + // handle required flag + ((!needflag) || + (TESTAFF(he->astr, needflag, he->alen) || + ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) + return he; + he = he->next_homonym; // check homonyms + } while (he); + + // obsolote stemming code (used only by the + // experimental SuffixMgr:suggest_pos_stems) + // store resulting root in wlst + } else if (wlst && (*ns < maxSug)) { + int cwrd = 1; + for (int k = 0; k < *ns; k++) + if (strcmp(tmpword, wlst[k]) == 0) { + cwrd = 0; + break; + } + if (cwrd) { + wlst[*ns] = mystrdup(tmpword); + if (wlst[*ns] == NULL) { + for (int j = 0; j < *ns; j++) + free(wlst[j]); + *ns = -1; + return NULL; + } + (*ns)++; + } + } + } + } + return NULL; +} + +// see if two-level suffix is present in the word +struct hentry* SfxEntry::check_twosfx(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag) { + struct hentry* he; // hash entry pointer + PfxEntry* ep = ppfx; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpword(word); + tmpword.resize(tmpl); + tmpword.append(strip); + tmpl += strip.size(); + + const char* beg = tmpword.c_str(); + const char* end = beg + tmpl; + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then recall suffix_check + + if (test_condition(end, beg)) { + if (ppfx) { + // handle conditional suffix + if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL, + (FLAG)aflag, needflag); + else + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx, NULL, 0, + NULL, (FLAG)aflag, needflag); + } else { + he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL, + (FLAG)aflag, needflag); + } + if (he) + return he; + } + } + return NULL; +} + +// see if two-level suffix is present in the word +char* SfxEntry::check_twosfx_morph(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag) { + PfxEntry* ep = ppfx; + char* st; + + char result[MAXLNLEN]; + + *result = '\0'; + + // if this suffix is being cross checked with a prefix + // but it does not support cross products skip it + + if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0) + return NULL; + + // upon entry suffix is 0 length or already matches the end of the word. + // So if the remaining root word has positive length + // and if there are enough chars in root word and added back strip chars + // to meet the number of characters conditions, then test it + + int tmpl = len - appnd.size(); // length of tmpword + + if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) && + (tmpl + strip.size() >= numconds)) { + // generate new root word by removing suffix and adding + // back any characters that would have been stripped or + // or null terminating the shorter string + + std::string tmpword(word); + tmpword.resize(tmpl); + tmpword.append(strip); + tmpl += strip.size(); + + const char* beg = tmpword.c_str(); + const char* end = beg + tmpl; + + // now make sure all of the conditions on characters + // are met. Please see the appendix at the end of + // this file for more info on exactly what is being + // tested + + // if all conditions are met then recall suffix_check + + if (test_condition(end, beg)) { + if (ppfx) { + // handle conditional suffix + if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, + needflag); + if (st) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } else { + st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag, + needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } + } else { + st = + pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + mychomp(result); + } + } + if (*result) + return mystrdup(result); + } + } + return NULL; +} + +// get next homonym with same affix +struct hentry* SfxEntry::get_next_homonym(struct hentry* he, + int optflags, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag) { + PfxEntry* ep = ppfx; + FLAG eFlag = ep ? ep->getFlag() : FLAG_NULL; + + while (he->next_homonym) { + he = he->next_homonym; + if ((TESTAFF(he->astr, aflag, he->alen) || + (ep && ep->getCont() && + TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && + ((optflags & aeXPRODUCT) == 0 || TESTAFF(he->astr, eFlag, he->alen) || + // handle conditional suffix + ((contclass) && TESTAFF(contclass, eFlag, contclasslen))) && + // handle cont. class + ((!cclass) || + ((contclass) && TESTAFF(contclass, cclass, contclasslen))) && + // handle required flag + ((!needflag) || + (TESTAFF(he->astr, needflag, he->alen) || + ((contclass) && TESTAFF(contclass, needflag, contclasslen))))) + return he; + } + return NULL; +} + +#if 0 + +Appendix: Understanding Affix Code + + +An affix is either a prefix or a suffix attached to root words to make +other words. + +Basically a Prefix or a Suffix is set of AffEntry objects +which store information about the prefix or suffix along +with supporting routines to check if a word has a particular +prefix or suffix or a combination. + +The structure affentry is defined as follows: + +struct affentry +{ + unsigned short aflag; // ID used to represent the affix + std::string strip; // string to strip before adding affix + std::string appnd; // the affix string to add + char numconds; // the number of conditions that must be met + char opts; // flag: aeXPRODUCT- combine both prefix and suffix + char conds[SETSIZE]; // array which encodes the conditions to be met +}; + + +Here is a suffix borrowed from the en_US.aff file. This file +is whitespace delimited. + +SFX D Y 4 +SFX D 0 e d +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +This information can be interpreted as follows: + +In the first line has 4 fields + +Field +----- +1 SFX - indicates this is a suffix +2 D - is the name of the character flag which represents this suffix +3 Y - indicates it can be combined with prefixes (cross product) +4 4 - indicates that sequence of 4 affentry structures are needed to + properly store the affix information + +The remaining lines describe the unique information for the 4 SfxEntry +objects that make up this affix. Each line can be interpreted +as follows: (note fields 1 and 2 are as a check against line 1 info) + +Field +----- +1 SFX - indicates this is a suffix +2 D - is the name of the character flag for this affix +3 y - the string of chars to strip off before adding affix + (a 0 here indicates the NULL string) +4 ied - the string of affix characters to add +5 [^aeiou]y - the conditions which must be met before the affix + can be applied + +Field 5 is interesting. Since this is a suffix, field 5 tells us that +there are 2 conditions that must be met. The first condition is that +the next to the last character in the word must *NOT* be any of the +following "a", "e", "i", "o" or "u". The second condition is that +the last character of the word must end in "y". + +So how can we encode this information concisely and be able to +test for both conditions in a fast manner? The answer is found +but studying the wonderful ispell code of Geoff Kuenning, et.al. +(now available under a normal BSD license). + +If we set up a conds array of 256 bytes indexed (0 to 255) and access it +using a character (cast to an unsigned char) of a string, we have 8 bits +of information we can store about that character. Specifically we +could use each bit to say if that character is allowed in any of the +last (or first for prefixes) 8 characters of the word. + +Basically, each character at one end of the word (up to the number +of conditions) is used to index into the conds array and the resulting +value found there says whether the that character is valid for a +specific character position in the word. + +For prefixes, it does this by setting bit 0 if that char is valid +in the first position, bit 1 if valid in the second position, and so on. + +If a bit is not set, then that char is not valid for that postion in the +word. + +If working with suffixes bit 0 is used for the character closest +to the front, bit 1 for the next character towards the end, ..., +with bit numconds-1 representing the last char at the end of the string. + +Note: since entries in the conds[] are 8 bits, only 8 conditions +(read that only 8 character positions) can be examined at one +end of a word (the beginning for prefixes and the end for suffixes. + +So to make this clearer, lets encode the conds array values for the +first two affentries for the suffix D described earlier. + + + For the first affentry: + numconds = 1 (only examine the last character) + + conds['e'] = (1 << 0) (the word must end in an E) + all others are all 0 + + For the second affentry: + numconds = 2 (only examine the last two characters) + + conds[X] = conds[X] | (1 << 0) (aeiou are not allowed) + where X is all characters *but* a, e, i, o, or u + + + conds['y'] = (1 << 1) (the last char must be a y) + all other bits for all other entries in the conds array are zero + +#endif diff --git a/extensions/spellcheck/hunspell/src/affentry.hxx b/extensions/spellcheck/hunspell/src/affentry.hxx new file mode 100644 index 000000000..6311d83ff --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affentry.hxx @@ -0,0 +1,232 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AFFIX_HXX_ +#define _AFFIX_HXX_ + +#include "hunvisapi.h" + +#include "atypes.hxx" +#include "baseaffix.hxx" +#include "affixmgr.hxx" + +/* A Prefix Entry */ + +class LIBHUNSPELL_DLL_EXPORTED PfxEntry : protected AffEntry { + private: + PfxEntry(const PfxEntry&); + PfxEntry& operator=(const PfxEntry&); + + private: + AffixMgr* pmyMgr; + + PfxEntry* next; + PfxEntry* nexteq; + PfxEntry* nextne; + PfxEntry* flgnxt; + + public: + PfxEntry(AffixMgr* pmgr, affentry* dp); + ~PfxEntry(); + + inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); } + struct hentry* checkword(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + struct hentry* check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + char* check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + char* check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + inline FLAG getFlag() { return aflag; } + inline const char* getKey() { return appnd.c_str(); } + char* add(const char* word, size_t len); + + inline short getKeyLen() { return appnd.size(); } + + inline const char* getMorph() { return morphcode; } + + inline const unsigned short* getCont() { return contclass; } + inline short getContLen() { return contclasslen; } + + inline PfxEntry* getNext() { return next; } + inline PfxEntry* getNextNE() { return nextne; } + inline PfxEntry* getNextEQ() { return nexteq; } + inline PfxEntry* getFlgNxt() { return flgnxt; } + + inline void setNext(PfxEntry* ptr) { next = ptr; } + inline void setNextNE(PfxEntry* ptr) { nextne = ptr; } + inline void setNextEQ(PfxEntry* ptr) { nexteq = ptr; } + inline void setFlgNxt(PfxEntry* ptr) { flgnxt = ptr; } + + inline char* nextchar(char* p); + inline int test_condition(const char* st); +}; + +/* A Suffix Entry */ + +class LIBHUNSPELL_DLL_EXPORTED SfxEntry : protected AffEntry { + private: + SfxEntry(const SfxEntry&); + SfxEntry& operator=(const SfxEntry&); + + private: + AffixMgr* pmyMgr; + std::string rappnd; + + SfxEntry* next; + SfxEntry* nexteq; + SfxEntry* nextne; + SfxEntry* flgnxt; + + SfxEntry* l_morph; + SfxEntry* r_morph; + SfxEntry* eq_morph; + + public: + SfxEntry(AffixMgr* pmgr, affentry* dp); + ~SfxEntry(); + + inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); } + struct hentry* checkword(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + const FLAG badflag = FLAG_NULL); + + struct hentry* check_twosfx(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* check_twosfx_morph(const char* word, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + struct hentry* get_next_homonym(struct hentry* he); + struct hentry* get_next_homonym(struct hentry* word, + int optflags, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag); + + inline FLAG getFlag() { return aflag; } + inline const char* getKey() { return rappnd.c_str(); } + char* add(const char* word, size_t len); + + inline const char* getMorph() { return morphcode; } + + inline const unsigned short* getCont() { return contclass; } + inline short getContLen() { return contclasslen; } + inline const char* getAffix() { return appnd.c_str(); } + + inline short getKeyLen() { return appnd.size(); } + + inline SfxEntry* getNext() { return next; } + inline SfxEntry* getNextNE() { return nextne; } + inline SfxEntry* getNextEQ() { return nexteq; } + + inline SfxEntry* getLM() { return l_morph; } + inline SfxEntry* getRM() { return r_morph; } + inline SfxEntry* getEQM() { return eq_morph; } + inline SfxEntry* getFlgNxt() { return flgnxt; } + + inline void setNext(SfxEntry* ptr) { next = ptr; } + inline void setNextNE(SfxEntry* ptr) { nextne = ptr; } + inline void setNextEQ(SfxEntry* ptr) { nexteq = ptr; } + inline void setFlgNxt(SfxEntry* ptr) { flgnxt = ptr; } + + inline char* nextchar(char* p); + inline int test_condition(const char* st, const char* begin); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/affixmgr.cxx b/extensions/spellcheck/hunspell/src/affixmgr.cxx new file mode 100644 index 000000000..d6bb67798 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affixmgr.cxx @@ -0,0 +1,5117 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include <algorithm> +#include <limits> +#include <string> +#include <vector> + +#include "affixmgr.hxx" +#include "affentry.hxx" +#include "langnum.hxx" + +#include "csutil.hxx" + +AffixMgr::AffixMgr(const char* affpath, + HashMgr** ptr, + int* md, + const char* key) { + // register hash manager and load affix data from aff file + pHMgr = ptr[0]; + alldic = ptr; + maxdic = md; + keystring = NULL; + trystring = NULL; + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + maptable = NULL; + nummap = 0; + breaktable = NULL; + numbreak = -1; + reptable = NULL; + numrep = 0; + iconvtable = NULL; + oconvtable = NULL; + checkcpdtable = NULL; + // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN) + simplifiedcpd = 0; + numcheckcpd = 0; + defcpdtable = NULL; + numdefcpd = 0; + phone = NULL; + compoundflag = FLAG_NULL; // permits word in compound forms + compoundbegin = FLAG_NULL; // may be first word in compound forms + compoundmiddle = FLAG_NULL; // may be middle word in compound forms + compoundend = FLAG_NULL; // may be last word in compound forms + compoundroot = FLAG_NULL; // compound word signing flag + compoundpermitflag = FLAG_NULL; // compound permitting flag for suffixed word + compoundforbidflag = FLAG_NULL; // compound fordidden flag for suffixed word + compoundmoresuffixes = 0; // allow more suffixes within compound words + checkcompounddup = 0; // forbid double words in compounds + checkcompoundrep = 0; // forbid bad compounds (may be non compound word with + // a REP substitution) + checkcompoundcase = + 0; // forbid upper and lowercase combinations at word bounds + checkcompoundtriple = 0; // forbid compounds with triple letters + simplifiedtriple = 0; // allow simplified triple letters in compounds + // (Schiff+fahrt -> Schiffahrt) + forbiddenword = FORBIDDENWORD; // forbidden word signing flag + nosuggest = FLAG_NULL; // don't suggest words signed with NOSUGGEST flag + nongramsuggest = FLAG_NULL; + lang = NULL; // language + langnum = 0; // language code (see http://l10n.openoffice.org/languages.html) + needaffix = FLAG_NULL; // forbidden root, allowed only with suffixes + cpdwordmax = -1; // default: unlimited wordcount in compound words + cpdmin = -1; // undefined + cpdmaxsyllable = 0; // default: unlimited syllablecount in compound words + cpdvowels = NULL; // vowels (for calculating of Hungarian compounding limit, + // O(n) search! XXX) + cpdvowels_utf16 = + NULL; // vowels for UTF-8 encoding (bsearch instead of O(n) search) + cpdvowels_utf16_len = 0; // vowels + pfxappnd = NULL; // previous prefix for counting syllables of the prefix BUG + sfxappnd = NULL; // previous suffix for counting syllables of the suffix BUG + sfxextra = 0; // modifier for syllable count of sfxappnd BUG + cpdsyllablenum = NULL; // syllable count incrementing flag + checknum = 0; // checking numbers, and word with numbers + wordchars = NULL; // letters + spec. word characters + ignorechars = NULL; // letters + spec. word characters + version = NULL; // affix and dictionary file version string + havecontclass = 0; // flags of possible continuing classes (double affix) + // LEMMA_PRESENT: not put root into the morphological output. Lemma presents + // in morhological description in dictionary file. It's often combined with + // PSEUDOROOT. + lemma_present = FLAG_NULL; + circumfix = FLAG_NULL; + onlyincompound = FLAG_NULL; + maxngramsugs = -1; // undefined + maxdiff = -1; // undefined + onlymaxdiff = 0; + maxcpdsugs = -1; // undefined + nosplitsugs = 0; + sugswithdots = 0; + keepcase = 0; + forceucase = 0; + warn = 0; + forbidwarn = 0; + checksharps = 0; + substandard = FLAG_NULL; + fullstrip = 0; + + sfx = NULL; + pfx = NULL; + + for (int i = 0; i < SETSIZE; i++) { + pStart[i] = NULL; + sStart[i] = NULL; + pFlag[i] = NULL; + sFlag[i] = NULL; + } + + for (int j = 0; j < CONTSIZE; j++) { + contclasses[j] = 0; + } + + if (parse_file(affpath, key)) { + HUNSPELL_WARNING(stderr, "Failure loading aff file %s\n", affpath); + } + + if (cpdmin == -1) + cpdmin = MINCPDLEN; +} + +AffixMgr::~AffixMgr() { + // pass through linked prefix entries and clean up + for (int i = 0; i < SETSIZE; i++) { + pFlag[i] = NULL; + PfxEntry* ptr = pStart[i]; + PfxEntry* nptr = NULL; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + nptr = NULL; + } + } + + // pass through linked suffix entries and clean up + for (int j = 0; j < SETSIZE; j++) { + sFlag[j] = NULL; + SfxEntry* ptr = sStart[j]; + SfxEntry* nptr = NULL; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + nptr = NULL; + } + sStart[j] = NULL; + } + + if (keystring) + free(keystring); + keystring = NULL; + if (trystring) + free(trystring); + trystring = NULL; + if (encoding) + free(encoding); + encoding = NULL; + if (maptable) { + for (int j = 0; j < nummap; j++) { + for (int k = 0; k < maptable[j].len; k++) { + if (maptable[j].set[k]) + free(maptable[j].set[k]); + } + free(maptable[j].set); + maptable[j].set = NULL; + maptable[j].len = 0; + } + free(maptable); + maptable = NULL; + } + nummap = 0; + if (breaktable) { + for (int j = 0; j < numbreak; j++) { + if (breaktable[j]) + free(breaktable[j]); + breaktable[j] = NULL; + } + free(breaktable); + breaktable = NULL; + } + numbreak = 0; + if (reptable) { + for (int j = 0; j < numrep; j++) { + free(reptable[j].pattern); + free(reptable[j].pattern2); + } + free(reptable); + reptable = NULL; + } + if (iconvtable) + delete iconvtable; + if (oconvtable) + delete oconvtable; + if (phone && phone->rules) { + for (int j = 0; j < phone->num + 1; j++) { + free(phone->rules[j * 2]); + free(phone->rules[j * 2 + 1]); + } + free(phone->rules); + free(phone); + phone = NULL; + } + + if (defcpdtable) { + for (int j = 0; j < numdefcpd; j++) { + free(defcpdtable[j].def); + defcpdtable[j].def = NULL; + } + free(defcpdtable); + defcpdtable = NULL; + } + numrep = 0; + if (checkcpdtable) { + for (int j = 0; j < numcheckcpd; j++) { + free(checkcpdtable[j].pattern); + free(checkcpdtable[j].pattern2); + free(checkcpdtable[j].pattern3); + checkcpdtable[j].pattern = NULL; + checkcpdtable[j].pattern2 = NULL; + checkcpdtable[j].pattern3 = NULL; + } + free(checkcpdtable); + checkcpdtable = NULL; + } + numcheckcpd = 0; + FREE_FLAG(compoundflag); + FREE_FLAG(compoundbegin); + FREE_FLAG(compoundmiddle); + FREE_FLAG(compoundend); + FREE_FLAG(compoundpermitflag); + FREE_FLAG(compoundforbidflag); + FREE_FLAG(compoundroot); + FREE_FLAG(forbiddenword); + FREE_FLAG(nosuggest); + FREE_FLAG(nongramsuggest); + FREE_FLAG(needaffix); + FREE_FLAG(lemma_present); + FREE_FLAG(circumfix); + FREE_FLAG(onlyincompound); + + cpdwordmax = 0; + pHMgr = NULL; + cpdmin = 0; + cpdmaxsyllable = 0; + if (cpdvowels) + free(cpdvowels); + if (cpdvowels_utf16) + free(cpdvowels_utf16); + if (cpdsyllablenum) + free(cpdsyllablenum); + free_utf_tbl(); + if (lang) + free(lang); + if (wordchars) + free(wordchars); + if (ignorechars) + free(ignorechars); + if (version) + free(version); + checknum = 0; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +void AffixMgr::finishFileMgr(FileMgr* afflst) { + delete afflst; + + // convert affix trees to sorted list + process_pfx_tree_to_list(); + process_sfx_tree_to_list(); +} + +// read in aff file and build up prefix and suffix entry objects +int AffixMgr::parse_file(const char* affpath, const char* key) { + char* line; // io buffers + char ft; // affix type + + // checking flag duplication + char dupflags[CONTSIZE]; + char dupflags_ini = 1; + + // first line indicator for removing byte order mark + int firstline = 1; + + // open the affix file + FileMgr* afflst = new FileMgr(affpath, key); + if (!afflst) { + HUNSPELL_WARNING( + stderr, "error: could not open affix description file %s\n", affpath); + return 1; + } + + // step one is to parse the affix file building up the internal + // affix data structures + + // read in each line ignoring any that do not + // start with a known line type indicator + while ((line = afflst->getline()) != NULL) { + mychomp(line); + + /* remove byte order mark */ + if (firstline) { + firstline = 0; + // Affix file begins with byte order mark: possible incompatibility with + // old Hunspell versions + if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) { + memmove(line, line + 3, strlen(line + 3) + 1); + } + } + + /* parse in the keyboard string */ + if (strncmp(line, "KEY", 3) == 0) { + if (parse_string(line, &keystring, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the try string */ + if (strncmp(line, "TRY", 3) == 0) { + if (parse_string(line, &trystring, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the name of the character set used by the .dict and .aff */ + if (strncmp(line, "SET", 3) == 0) { + if (parse_string(line, &encoding, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + if (strcmp(encoding, "UTF-8") == 0) { + utf8 = 1; +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + if (initialize_utf_tbl()) { + finishFileMgr(afflst); + return 1; + } +#endif +#endif + } + } + + /* parse COMPLEXPREFIXES for agglutinative languages with right-to-left + * writing system */ + if (strncmp(line, "COMPLEXPREFIXES", 15) == 0) + complexprefixes = 1; + + /* parse in the flag used by the controlled compound words */ + if (strncmp(line, "COMPOUNDFLAG", 12) == 0) { + if (parse_flag(line, &compoundflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDBEGIN", 13) == 0) { + if (complexprefixes) { + if (parse_flag(line, &compoundend, afflst)) { + finishFileMgr(afflst); + return 1; + } + } else { + if (parse_flag(line, &compoundbegin, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + } + + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDMIDDLE", 14) == 0) { + if (parse_flag(line, &compoundmiddle, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + /* parse in the flag used by compound words */ + if (strncmp(line, "COMPOUNDEND", 11) == 0) { + if (complexprefixes) { + if (parse_flag(line, &compoundbegin, afflst)) { + finishFileMgr(afflst); + return 1; + } + } else { + if (parse_flag(line, &compoundend, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + } + + /* parse in the data used by compound_check() method */ + if (strncmp(line, "COMPOUNDWORDMAX", 15) == 0) { + if (parse_num(line, &cpdwordmax, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag sign compounds in dictionary */ + if (strncmp(line, "COMPOUNDROOT", 12) == 0) { + if (parse_flag(line, &compoundroot, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "COMPOUNDPERMITFLAG", 18) == 0) { + if (parse_flag(line, &compoundpermitflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "COMPOUNDFORBIDFLAG", 18) == 0) { + if (parse_flag(line, &compoundforbidflag, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "COMPOUNDMORESUFFIXES", 20) == 0) { + compoundmoresuffixes = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDDUP", 16) == 0) { + checkcompounddup = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDREP", 16) == 0) { + checkcompoundrep = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDTRIPLE", 19) == 0) { + checkcompoundtriple = 1; + } + + if (strncmp(line, "SIMPLIFIEDTRIPLE", 16) == 0) { + simplifiedtriple = 1; + } + + if (strncmp(line, "CHECKCOMPOUNDCASE", 17) == 0) { + checkcompoundcase = 1; + } + + if (strncmp(line, "NOSUGGEST", 9) == 0) { + if (parse_flag(line, &nosuggest, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "NONGRAMSUGGEST", 14) == 0) { + if (parse_flag(line, &nongramsuggest, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "FORBIDDENWORD", 13) == 0) { + if (parse_flag(line, &forbiddenword, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "LEMMA_PRESENT", 13) == 0) { + if (parse_flag(line, &lemma_present, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by circumfixes */ + if (strncmp(line, "CIRCUMFIX", 9) == 0) { + if (parse_flag(line, &circumfix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by fogemorphemes */ + if (strncmp(line, "ONLYINCOMPOUND", 14) == 0) { + if (parse_flag(line, &onlyincompound, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `needaffixs' */ + if (strncmp(line, "PSEUDOROOT", 10) == 0) { + if (parse_flag(line, &needaffix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `needaffixs' */ + if (strncmp(line, "NEEDAFFIX", 9) == 0) { + if (parse_flag(line, &needaffix, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the minimal length for words in compounds */ + if (strncmp(line, "COMPOUNDMIN", 11) == 0) { + if (parse_num(line, &cpdmin, afflst)) { + finishFileMgr(afflst); + return 1; + } + if (cpdmin < 1) + cpdmin = 1; + } + + /* parse in the max. words and syllables in compounds */ + if (strncmp(line, "COMPOUNDSYLLABLE", 16) == 0) { + if (parse_cpdsyllable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by compound_check() method */ + if (strncmp(line, "SYLLABLENUM", 11) == 0) { + if (parse_string(line, &cpdsyllablenum, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by the controlled compound words */ + if (strncmp(line, "CHECKNUM", 8) == 0) { + checknum = 1; + } + + /* parse in the extra word characters */ + if (strncmp(line, "WORDCHARS", 9) == 0) { + if (!parse_array(line, &wordchars, wordchars_utf16, + utf8, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the ignored characters (for example, Arabic optional diacretics + * charachters */ + if (strncmp(line, "IGNORE", 6) == 0) { + if (!parse_array(line, &ignorechars, ignorechars_utf16, + utf8, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the typical fault correcting table */ + if (strncmp(line, "REP", 3) == 0) { + if (parse_reptable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the input conversion table */ + if (strncmp(line, "ICONV", 5) == 0) { + if (parse_convtable(line, afflst, &iconvtable, "ICONV")) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the input conversion table */ + if (strncmp(line, "OCONV", 5) == 0) { + if (parse_convtable(line, afflst, &oconvtable, "OCONV")) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the phonetic translation table */ + if (strncmp(line, "PHONE", 5) == 0) { + if (parse_phonetable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the checkcompoundpattern table */ + if (strncmp(line, "CHECKCOMPOUNDPATTERN", 20) == 0) { + if (parse_checkcpdtable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the defcompound table */ + if (strncmp(line, "COMPOUNDRULE", 12) == 0) { + if (parse_defcpdtable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the related character map table */ + if (strncmp(line, "MAP", 3) == 0) { + if (parse_maptable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the word breakpoints table */ + if (strncmp(line, "BREAK", 5) == 0) { + if (parse_breaktable(line, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the language for language specific codes */ + if (strncmp(line, "LANG", 4) == 0) { + if (parse_string(line, &lang, afflst->getlinenum())) { + finishFileMgr(afflst); + return 1; + } + langnum = get_lang_num(lang); + } + + if (strncmp(line, "VERSION", 7) == 0) { + for (line = line + 7; *line == ' ' || *line == '\t'; line++) + ; + version = mystrdup(line); + } + + if (strncmp(line, "MAXNGRAMSUGS", 12) == 0) { + if (parse_num(line, &maxngramsugs, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "ONLYMAXDIFF", 11) == 0) + onlymaxdiff = 1; + + if (strncmp(line, "MAXDIFF", 7) == 0) { + if (parse_num(line, &maxdiff, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "MAXCPDSUGS", 10) == 0) { + if (parse_num(line, &maxcpdsugs, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "NOSPLITSUGS", 11) == 0) { + nosplitsugs = 1; + } + + if (strncmp(line, "FULLSTRIP", 9) == 0) { + fullstrip = 1; + } + + if (strncmp(line, "SUGSWITHDOTS", 12) == 0) { + sugswithdots = 1; + } + + /* parse in the flag used by forbidden words */ + if (strncmp(line, "KEEPCASE", 8) == 0) { + if (parse_flag(line, &keepcase, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `forceucase' */ + if (strncmp(line, "FORCEUCASE", 10) == 0) { + if (parse_flag(line, &forceucase, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + /* parse in the flag used by `warn' */ + if (strncmp(line, "WARN", 4) == 0) { + if (parse_flag(line, &warn, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "FORBIDWARN", 10) == 0) { + forbidwarn = 1; + } + + /* parse in the flag used by the affix generator */ + if (strncmp(line, "SUBSTANDARD", 11) == 0) { + if (parse_flag(line, &substandard, afflst)) { + finishFileMgr(afflst); + return 1; + } + } + + if (strncmp(line, "CHECKSHARPS", 11) == 0) { + checksharps = 1; + } + + /* parse this affix: P - prefix, S - suffix */ + ft = ' '; + if (strncmp(line, "PFX", 3) == 0) + ft = complexprefixes ? 'S' : 'P'; + if (strncmp(line, "SFX", 3) == 0) + ft = complexprefixes ? 'P' : 'S'; + if (ft != ' ') { + if (dupflags_ini) { + memset(dupflags, 0, sizeof(dupflags)); + dupflags_ini = 0; + } + if (parse_affix(line, ft, afflst, dupflags)) { + finishFileMgr(afflst); + return 1; + } + } + } + + finishFileMgr(afflst); + // affix trees are sorted now + + // now we can speed up performance greatly taking advantage of the + // relationship between the affixes and the idea of "subsets". + + // View each prefix as a potential leading subset of another and view + // each suffix (reversed) as a potential trailing subset of another. + + // To illustrate this relationship if we know the prefix "ab" is found in the + // word to examine, only prefixes that "ab" is a leading subset of need be + // examined. + // Furthermore is "ab" is not present then none of the prefixes that "ab" is + // is a subset need be examined. + // The same argument goes for suffix string that are reversed. + + // Then to top this off why not examine the first char of the word to quickly + // limit the set of prefixes to examine (i.e. the prefixes to examine must + // be leading supersets of the first character of the word (if they exist) + + // To take advantage of this "subset" relationship, we need to add two links + // from entry. One to take next if the current prefix is found (call it + // nexteq) + // and one to take next if the current prefix is not found (call it nextne). + + // Since we have built ordered lists, all that remains is to properly + // initialize + // the nextne and nexteq pointers that relate them + + process_pfx_order(); + process_sfx_order(); + + /* get encoding for CHECKCOMPOUNDCASE */ + if (!utf8) { + char* enc = get_encoding(); + csconv = get_current_cs(enc); + free(enc); + enc = NULL; + + std::string expw; + if (wordchars) { + expw.assign(wordchars); + free(wordchars); + } + + for (int i = 0; i <= 255; i++) { + if ((csconv[i].cupper != csconv[i].clower) && + (expw.find((char)i) == std::string::npos)) { + expw.push_back((char)i); + } + } + + wordchars = mystrdup(expw.c_str()); + } + + // default BREAK definition + if (numbreak == -1) { + breaktable = (char**)malloc(sizeof(char*) * 3); + if (!breaktable) + return 1; + breaktable[0] = mystrdup("-"); + breaktable[1] = mystrdup("^-"); + breaktable[2] = mystrdup("-$"); + if (breaktable[0] && breaktable[1] && breaktable[2]) + numbreak = 3; + } + return 0; +} + +// we want to be able to quickly access prefix information +// both by prefix flag, and sorted by prefix string itself +// so we need to set up two indexes + +int AffixMgr::build_pfxtree(PfxEntry* pfxptr) { + PfxEntry* ptr; + PfxEntry* pptr; + PfxEntry* ep = pfxptr; + + // get the right starting points + const char* key = ep->getKey(); + const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); + + // first index by flag which must exist + ptr = pFlag[flg]; + ep->setFlgNxt(ptr); + pFlag[flg] = ep; + + // handle the special case of null affix string + if (strlen(key) == 0) { + // always inset them at head of list at element 0 + ptr = pStart[0]; + ep->setNext(ptr); + pStart[0] = ep; + return 0; + } + + // now handle the normal case + ep->setNextEQ(NULL); + ep->setNextNE(NULL); + + unsigned char sp = *((const unsigned char*)key); + ptr = pStart[sp]; + + // handle the first insert + if (!ptr) { + pStart[sp] = ep; + return 0; + } + + // otherwise use binary tree insertion so that a sorted + // list can easily be generated later + pptr = NULL; + for (;;) { + pptr = ptr; + if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { + ptr = ptr->getNextEQ(); + if (!ptr) { + pptr->setNextEQ(ep); + break; + } + } else { + ptr = ptr->getNextNE(); + if (!ptr) { + pptr->setNextNE(ep); + break; + } + } + } + return 0; +} + +// we want to be able to quickly access suffix information +// both by suffix flag, and sorted by the reverse of the +// suffix string itself; so we need to set up two indexes +int AffixMgr::build_sfxtree(SfxEntry* sfxptr) { + SfxEntry* ptr; + SfxEntry* pptr; + SfxEntry* ep = sfxptr; + + /* get the right starting point */ + const char* key = ep->getKey(); + const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF); + + // first index by flag which must exist + ptr = sFlag[flg]; + ep->setFlgNxt(ptr); + sFlag[flg] = ep; + + // next index by affix string + + // handle the special case of null affix string + if (strlen(key) == 0) { + // always inset them at head of list at element 0 + ptr = sStart[0]; + ep->setNext(ptr); + sStart[0] = ep; + return 0; + } + + // now handle the normal case + ep->setNextEQ(NULL); + ep->setNextNE(NULL); + + unsigned char sp = *((const unsigned char*)key); + ptr = sStart[sp]; + + // handle the first insert + if (!ptr) { + sStart[sp] = ep; + return 0; + } + + // otherwise use binary tree insertion so that a sorted + // list can easily be generated later + pptr = NULL; + for (;;) { + pptr = ptr; + if (strcmp(ep->getKey(), ptr->getKey()) <= 0) { + ptr = ptr->getNextEQ(); + if (!ptr) { + pptr->setNextEQ(ep); + break; + } + } else { + ptr = ptr->getNextNE(); + if (!ptr) { + pptr->setNextNE(ep); + break; + } + } + } + return 0; +} + +// convert from binary tree to sorted list +int AffixMgr::process_pfx_tree_to_list() { + for (int i = 1; i < SETSIZE; i++) { + pStart[i] = process_pfx_in_order(pStart[i], NULL); + } + return 0; +} + +PfxEntry* AffixMgr::process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr) { + if (ptr) { + nptr = process_pfx_in_order(ptr->getNextNE(), nptr); + ptr->setNext(nptr); + nptr = process_pfx_in_order(ptr->getNextEQ(), ptr); + } + return nptr; +} + +// convert from binary tree to sorted list +int AffixMgr::process_sfx_tree_to_list() { + for (int i = 1; i < SETSIZE; i++) { + sStart[i] = process_sfx_in_order(sStart[i], NULL); + } + return 0; +} + +SfxEntry* AffixMgr::process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr) { + if (ptr) { + nptr = process_sfx_in_order(ptr->getNextNE(), nptr); + ptr->setNext(nptr); + nptr = process_sfx_in_order(ptr->getNextEQ(), ptr); + } + return nptr; +} + +// reinitialize the PfxEntry links NextEQ and NextNE to speed searching +// using the idea of leading subsets this time +int AffixMgr::process_pfx_order() { + PfxEntry* ptr; + + // loop through each prefix list starting point + for (int i = 1; i < SETSIZE; i++) { + ptr = pStart[i]; + + // look through the remainder of the list + // and find next entry with affix that + // the current one is not a subset of + // mark that as destination for NextNE + // use next in list that you are a subset + // of as NextEQ + + for (; ptr != NULL; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(NULL); + if ((ptr->getNext()) && + isSubset(ptr->getKey(), (ptr->getNext())->getKey())) + ptr->setNextEQ(ptr->getNext()); + } + + // now clean up by adding smart search termination strings: + // if you are already a superset of the previous prefix + // but not a subset of the next, search can end here + // so set NextNE properly + + ptr = pStart[i]; + for (; ptr != NULL; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + PfxEntry* mptr = NULL; + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(NULL); + } + } + return 0; +} + +// initialize the SfxEntry links NextEQ and NextNE to speed searching +// using the idea of leading subsets this time +int AffixMgr::process_sfx_order() { + SfxEntry* ptr; + + // loop through each prefix list starting point + for (int i = 1; i < SETSIZE; i++) { + ptr = sStart[i]; + + // look through the remainder of the list + // and find next entry with affix that + // the current one is not a subset of + // mark that as destination for NextNE + // use next in list that you are a subset + // of as NextEQ + + for (; ptr != NULL; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(NULL); + if ((ptr->getNext()) && + isSubset(ptr->getKey(), (ptr->getNext())->getKey())) + ptr->setNextEQ(ptr->getNext()); + } + + // now clean up by adding smart search termination strings: + // if you are already a superset of the previous suffix + // but not a subset of the next, search can end here + // so set NextNE properly + + ptr = sStart[i]; + for (; ptr != NULL; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + SfxEntry* mptr = NULL; + for (; nptr != NULL; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(NULL); + } + } + return 0; +} + +// add flags to the result for dictionary debugging +void AffixMgr::debugflag(char* result, unsigned short flag) { + char* st = encode_flag(flag); + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_FLAG, MAXLNLEN); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } +} + +// add flags to the result for dictionary debugging +std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) { + char* st = encode_flag(flag); + result.append(" "); + result.append(MORPH_FLAG); + if (st) { + result.append(st); + free(st); + } + return result; +} + +// calculate the character length of the condition +int AffixMgr::condlen(const char* st) { + int l = 0; + bool group = false; + for (; *st; st++) { + if (*st == '[') { + group = true; + l++; + } else if (*st == ']') + group = false; + else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80)))) + l++; + } + return l; +} + +int AffixMgr::encodeit(affentry& entry, const char* cs) { + if (strcmp(cs, ".") != 0) { + entry.numconds = (char)condlen(cs); + // coverity[buffer_size_warning] - deliberate use of lack of end of conds + // padded by strncpy as long condition flag + strncpy(entry.c.conds, cs, MAXCONDLEN); + if (entry.c.conds[MAXCONDLEN - 1] && cs[MAXCONDLEN]) { + entry.opts += aeLONGCOND; + entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1); + if (!entry.c.l.conds2) + return 1; + } + } else { + entry.numconds = 0; + entry.c.conds[0] = '\0'; + } + return 0; +} + +// return 1 if s1 is a leading subset of s2 (dots are for infixes) +inline int AffixMgr::isSubset(const char* s1, const char* s2) { + while (((*s1 == *s2) || (*s1 == '.')) && (*s1 != '\0')) { + s1++; + s2++; + } + return (*s1 == '\0'); +} + +// check word for prefixes +struct hentry* AffixMgr::prefix_check(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = NULL; + + pfx = NULL; + pfxappnd = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + if ( + // fogemorpheme + ((in_compound != IN_CPD_NOT) || + !(pe->getCont() && + (TESTAFF(pe->getCont(), onlyincompound, pe->getContLen())))) && + // permit prefixes in compounds + ((in_compound != IN_CPD_END) || + (pe->getCont() && + (TESTAFF(pe->getCont(), compoundpermitflag, pe->getContLen()))))) { + // check prefix + rv = pe->checkword(word, len, in_compound, needflag); + if (rv) { + pfx = pe; // BUG: pfx not stateless + return rv; + } + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + if ( + // fogemorpheme + ((in_compound != IN_CPD_NOT) || + !(pptr->getCont() && + (TESTAFF(pptr->getCont(), onlyincompound, pptr->getContLen())))) && + // permit prefixes in compounds + ((in_compound != IN_CPD_END) || + (pptr->getCont() && (TESTAFF(pptr->getCont(), compoundpermitflag, + pptr->getContLen()))))) { + // check prefix + rv = pptr->checkword(word, len, in_compound, needflag); + if (rv) { + pfx = pptr; // BUG: pfx not stateless + return rv; + } + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return NULL; +} + +// check word for prefixes +struct hentry* AffixMgr::prefix_check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = NULL; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + + while (pe) { + rv = pe->check_twosfx(word, len, in_compound, needflag); + if (rv) + return rv; + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + rv = pptr->check_twosfx(word, len, in_compound, needflag); + if (rv) { + pfx = pptr; + return rv; + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return NULL; +} + +// check word for prefixes +char* AffixMgr::prefix_check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + + char result[MAXLNLEN]; + result[0] = '\0'; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + char* st = pe->check_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + // if (rv) return rv; + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + char* st = pptr->check_morph(word, len, in_compound, needflag); + if (st) { + // fogemorpheme + if ((in_compound != IN_CPD_NOT) || + !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound, + pptr->getContLen()))))) { + mystrcat(result, st, MAXLNLEN); + pfx = pptr; + } + free(st); + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// check word for prefixes +char* AffixMgr::prefix_check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag) { + char result[MAXLNLEN]; + result[0] = '\0'; + + pfx = NULL; + sfxappnd = NULL; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + char* st = pe->check_twosfx_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = *((const unsigned char*)word); + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word)) { + char* st = pptr->check_twosfx_morph(word, len, in_compound, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + pfx = pptr; + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// Is word a non compound with a REP substitution (see checkcompoundrep)? +int AffixMgr::cpdrep_check(const char* word, int wl) { + + if ((wl < 2) || !numrep) + return 0; + + for (int i = 0; i < numrep; i++) { + const char* r = word; + int lenp = strlen(reptable[i].pattern); + // search every occurence of the pattern in the word + while ((r = strstr(r, reptable[i].pattern)) != NULL) { + std::string candidate(word); + candidate.replace(r - word, lenp, reptable[i].pattern2); + if (candidate_check(candidate.c_str(), candidate.size())) + return 1; + r++; // search for the next letter + } + } + return 0; +} + +// forbid compoundings when there are special patterns at word bound +int AffixMgr::cpdpat_check(const char* word, + int pos, + hentry* r1, + hentry* r2, + const char /*affixed*/) { + int len; + for (int i = 0; i < numcheckcpd; i++) { + if (isSubset(checkcpdtable[i].pattern2, word + pos) && + (!r1 || !checkcpdtable[i].cond || + (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) && + (!r2 || !checkcpdtable[i].cond2 || + (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) && + // zero length pattern => only TESTAFF + // zero pattern (0/flag) => unmodified stem (zero affixes allowed) + (!*(checkcpdtable[i].pattern) || + ((*(checkcpdtable[i].pattern) == '0' && r1->blen <= pos && + strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) || + (*(checkcpdtable[i].pattern) != '0' && + ((len = strlen(checkcpdtable[i].pattern)) != 0) && + strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)))) { + return 1; + } + } + return 0; +} + +// forbid compounding with neighbouring upper and lower case characters at word +// bounds +int AffixMgr::cpdcase_check(const char* word, int pos) { + if (utf8) { + const char* p; + for (p = word + pos - 1; (*p & 0xc0) == 0x80; p--) + ; + std::string pair(p); + std::vector<w_char> pair_u; + u8_u16(pair_u, pair); + unsigned short a = pair_u.size() > 1 ? ((pair_u[1].h << 8) + pair_u[1].l) : 0; + unsigned short b = !pair_u.empty() ? ((pair_u[0].h << 8) + pair_u[0].l) : 0; + if (((unicodetoupper(a, langnum) == a) || + (unicodetoupper(b, langnum) == b)) && + (a != '-') && (b != '-')) + return 1; + } else { + unsigned char a = *(word + pos - 1); + unsigned char b = *(word + pos); + if ((csconv[a].ccase || csconv[b].ccase) && (a != '-') && (b != '-')) + return 1; + } + return 0; +} + +struct metachar_data { + signed short btpp; // metacharacter (*, ?) position for backtracking + signed short btwp; // word position for metacharacters + int btnum; // number of matched characters in metacharacter +}; + +// check compound patterns +int AffixMgr::defcpd_check(hentry*** words, + short wnum, + hentry* rv, + hentry** def, + char all) { + int w = 0; + + if (!*words) { + w = 1; + *words = def; + } + + if (!*words) { + return 0; + } + + std::vector<metachar_data> btinfo(1); + + short bt = 0; + int i, j; + + (*words)[wnum] = rv; + + // has the last word COMPOUNDRULE flag? + if (rv->alen == 0) { + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; + } + int ok = 0; + for (i = 0; i < numdefcpd; i++) { + for (j = 0; j < defcpdtable[i].len; j++) { + if (defcpdtable[i].def[j] != '*' && defcpdtable[i].def[j] != '?' && + TESTAFF(rv->astr, defcpdtable[i].def[j], rv->alen)) { + ok = 1; + break; + } + } + } + if (ok == 0) { + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; + } + + for (i = 0; i < numdefcpd; i++) { + signed short pp = 0; // pattern position + signed short wp = 0; // "words" position + int ok2; + ok = 1; + ok2 = 1; + do { + while ((pp < defcpdtable[i].len) && (wp <= wnum)) { + if (((pp + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[pp + 1] == '*') || + (defcpdtable[i].def[pp + 1] == '?'))) { + int wend = (defcpdtable[i].def[pp + 1] == '?') ? wp : wnum; + ok2 = 1; + pp += 2; + btinfo[bt].btpp = pp; + btinfo[bt].btwp = wp; + while (wp <= wend) { + if (!(*words)[wp]->alen || + !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp - 2], + (*words)[wp]->alen)) { + ok2 = 0; + break; + } + wp++; + } + if (wp <= wnum) + ok2 = 0; + btinfo[bt].btnum = wp - btinfo[bt].btwp; + if (btinfo[bt].btnum > 0) { + ++bt; + btinfo.resize(bt+1); + } + if (ok2) + break; + } else { + ok2 = 1; + if (!(*words)[wp] || !(*words)[wp]->alen || + !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp], + (*words)[wp]->alen)) { + ok = 0; + break; + } + pp++; + wp++; + if ((defcpdtable[i].len == pp) && !(wp > wnum)) + ok = 0; + } + } + if (ok && ok2) { + int r = pp; + while ((defcpdtable[i].len > r) && ((r + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[r + 1] == '*') || + (defcpdtable[i].def[r + 1] == '?'))) + r += 2; + if (defcpdtable[i].len <= r) + return 1; + } + // backtrack + if (bt) + do { + ok = 1; + btinfo[bt - 1].btnum--; + pp = btinfo[bt - 1].btpp; + wp = btinfo[bt - 1].btwp + (signed short)btinfo[bt - 1].btnum; + } while ((btinfo[bt - 1].btnum < 0) && --bt); + } while (bt); + + if (ok && ok2 && (!all || (defcpdtable[i].len <= pp))) + return 1; + + // check zero ending + while (ok && ok2 && (defcpdtable[i].len > pp) && + ((pp + 1) < defcpdtable[i].len) && + ((defcpdtable[i].def[pp + 1] == '*') || + (defcpdtable[i].def[pp + 1] == '?'))) + pp += 2; + if (ok && ok2 && (defcpdtable[i].len <= pp)) + return 1; + } + (*words)[wnum] = NULL; + if (w) + *words = NULL; + return 0; +} + +inline int AffixMgr::candidate_check(const char* word, int len) { + struct hentry* rv = NULL; + + rv = lookup(word); + if (rv) + return 1; + + // rv = prefix_check(word,len,1); + // if (rv) return 1; + + rv = affix_check(word, len); + if (rv) + return 1; + return 0; +} + +// calculate number of syllable for compound-checking +short AffixMgr::get_syllable(const std::string& word) { + if (cpdmaxsyllable == 0) + return 0; + + short num = 0; + + if (!utf8) { + for (size_t i = 0; i < word.size(); ++i) { + if (strchr(cpdvowels, word[i])) + num++; + } + } else if (cpdvowels_utf16) { + std::vector<w_char> w; + int i = u8_u16(w, word); + for (; i > 0; i--) { + if (std::binary_search(cpdvowels_utf16, + cpdvowels_utf16 + cpdvowels_utf16_len, + w[i - 1])) { + ++num; + } + } + } + return num; +} + +void AffixMgr::setcminmax(int* cmin, int* cmax, const char* word, int len) { + if (utf8) { + int i; + for (*cmin = 0, i = 0; (i < cpdmin) && *cmin < len; i++) { + for ((*cmin)++; *cmin < len && (word[*cmin] & 0xc0) == 0x80; (*cmin)++) + ; + } + for (*cmax = len, i = 0; (i < (cpdmin - 1)) && *cmax >= 0; i++) { + for ((*cmax)--; *cmax >= 0 && (word[*cmax] & 0xc0) == 0x80; (*cmax)--) + ; + } + } else { + *cmin = cpdmin; + *cmax = len - cpdmin + 1; + } +} + +// check if compound word is correctly spelled +// hu_mov_rule = spec. Hungarian rule (XXX) +struct hentry* AffixMgr::compound_check(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words = NULL, + hentry** rwords = NULL, + char hu_mov_rule = 0, + char is_sug = 0, + int* info = NULL) { + int i; + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + struct hentry* rv = NULL; + struct hentry* rv_first; + std::string st; + char ch = '\0'; + int cmin; + int cmax; + int striple = 0; + int scpd = 0; + int soldi = 0; + int oldcmin = 0; + int oldcmax = 0; + int oldlen = 0; + int checkedstriple = 0; + int onlycpdrule; + char affixed = 0; + hentry** oldwords = words; + + int checked_prefix; + + setcminmax(&cmin, &cmax, word, len); + + st.assign(word); + + for (i = cmin; i < cmax; i++) { + // go to end of the UTF-8 character + if (utf8) { + for (; (st[i] & 0xc0) == 0x80; i++) + ; + if (i >= cmax) + return NULL; + } + + words = oldwords; + onlycpdrule = (words) ? 1 : 0; + + do { // onlycpdrule loop + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + do { // simplified checkcompoundpattern loop + + if (scpd > 0) { + for (; scpd <= numcheckcpd && + (!checkcpdtable[scpd - 1].pattern3 || + strncmp(word + i, checkcpdtable[scpd - 1].pattern3, + strlen(checkcpdtable[scpd - 1].pattern3)) != 0); + scpd++) + ; + + if (scpd > numcheckcpd) + break; // break simplified checkcompoundpattern loop + st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern); + soldi = i; + i += strlen(checkcpdtable[scpd - 1].pattern); + st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern2); + st.replace(i + strlen(checkcpdtable[scpd - 1].pattern2), std::string::npos, + word + soldi + strlen(checkcpdtable[scpd - 1].pattern3)); + + oldlen = len; + len += strlen(checkcpdtable[scpd - 1].pattern) + + strlen(checkcpdtable[scpd - 1].pattern2) - + strlen(checkcpdtable[scpd - 1].pattern3); + oldcmin = cmin; + oldcmax = cmax; + setcminmax(&cmin, &cmax, st.c_str(), len); + + cmax = len - cpdmin + 1; + } + + ch = st[i]; + st[i] = '\0'; + + sfx = NULL; + pfx = NULL; + + // FIRST WORD + + affixed = 1; + rv = lookup(st.c_str()); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && !hu_mov_rule && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundbegin && !wordnum && !onlycpdrule && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + (compoundmiddle && wordnum && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) || + (numdefcpd && onlycpdrule && + ((!words && !wordnum && + defcpd_check(&words, wnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, rv, rwords, 0))))) || + (scpd != 0 && checkcpdtable[scpd - 1].cond != FLAG_NULL && + !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)))) { + rv = rv->next_homonym; + } + + if (rv) + affixed = 0; + + if (!rv) { + if (onlycpdrule) + break; + if (compoundflag && + !(rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundflag, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())) || + (compoundend && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundbegin))) || // twofold suffixes + compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check( + st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundmiddle))) || // twofold suffixes + compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundmiddle)))))) + checked_prefix = 1; + // else check forbiddenwords and needaffix + } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, needaffix, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) { + st[i] = ch; + // continue; + break; + } + + // check non_compound flag in suffix and prefix + if ((rv) && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check compoundend flag in suffix and prefix + if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + + // check compoundmiddle flag in suffix and prefix + if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && + !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) { + return NULL; + } + + // increment word number, if the second root has a compoundroot flag + if ((rv) && compoundroot && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // first word is acceptable in compound words? + if (((rv) && + (checked_prefix || (words && words[wnum]) || + (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + ((oldwordnum == 0) && compoundbegin && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + ((oldwordnum > 0) && compoundmiddle && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) // || + // (numdefcpd && ) + + // LANG_hu section: spec. Hungarian rule + || ((langnum == LANG_hu) && hu_mov_rule && + (TESTAFF( + rv->astr, 'F', + rv->alen) || // XXX hardwired Hungarian dictionary codes + TESTAFF(rv->astr, 'G', rv->alen) || + TESTAFF(rv->astr, 'H', rv->alen))) + // END of LANG_hu section + ) && + ( + // test CHECKCOMPOUNDPATTERN conditions + scpd == 0 || checkcpdtable[scpd - 1].cond == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)) && + !((checkcompoundtriple && scpd == 0 && + !words && // test triple letters + (word[i - 1] == word[i]) && + (((i > 1) && (word[i - 1] == word[i - 2])) || + ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' + )) || + (checkcompoundcase && scpd == 0 && !words && + cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && + (rv = affix_check(st.c_str(), i)) && + (sfx && sfx->getCont() && + ( // XXX hardwired Hungarian dic. codes + TESTAFF(sfx->getCont(), (unsigned short)'x', + sfx->getContLen()) || + TESTAFF( + sfx->getCont(), (unsigned short)'%', + sfx->getContLen()))))) { // first word is ok condition + + // LANG_hu section: spec. Hungarian rule + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(st.substr(i)); + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + } + // END of LANG_hu section + + // NEXT WORD(S) + rv_first = rv; + st[i] = ch; + + do { // striple loop + + // check simplifiedtriple + if (simplifiedtriple) { + if (striple) { + checkedstriple = 1; + i--; // check "fahrt" instead of "ahrt" in "Schiffahrt" + } else if (i > 2 && *(word + i - 1) == *(word + i - 2)) + striple = 1; + } + + rv = lookup(st.c_str() + i); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && !words && + TESTAFF(rv->astr, compoundend, rv->alen)) || + (numdefcpd && words && + defcpd_check(&words, wnum + 1, rv, NULL, 1))) || + (scpd != 0 && checkcpdtable[scpd - 1].cond2 != FLAG_NULL && + !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, + rv->alen)))) { + rv = rv->next_homonym; + } + + // check FORCEUCASE + if (rv && forceucase && (rv) && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = NULL; + + if (rv && words && words[wnum + 1]) + return rv_first; + + oldnumsyllable2 = numsyllable; + oldwordnum2 = wordnum; + + // LANG_hu section: spec. Hungarian rule, XXX hardwired dictionary + // code + if ((rv) && (langnum == LANG_hu) && + (TESTAFF(rv->astr, 'I', rv->alen)) && + !(TESTAFF(rv->astr, 'J', rv->alen))) { + numsyllable--; + } + // END of LANG_hu section + + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) + return NULL; + + // second word is acceptable, as a root? + // hungarian conventions: compounding is acceptable, + // when compound forms consist of 2 words, or if more, + // then the syllable number of root words must be 6, or lesser. + + if ((rv) && + ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && + (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->clen)) <= + cpdmaxsyllable))) && + ( + // test CHECKCOMPOUNDPATTERN + !numcheckcpd || scpd != 0 || + !cpdpat_check(word, i, rv_first, rv, 0)) && + ((!checkcompounddup || (rv != rv_first))) + // test CHECKCOMPOUNDPATTERN conditions + && + (scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = NULL; + sfxflag = FLAG_NULL; + rv = (compoundflag && !onlycpdrule) + ? affix_check((word + i), strlen(word + i), compoundflag, + IN_CPD_END) + : NULL; + if (!rv && compoundend && !onlycpdrule) { + sfx = NULL; + pfx = NULL; + rv = affix_check((word + i), strlen(word + i), compoundend, + IN_CPD_END); + } + + if (!rv && numdefcpd && words) { + rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END); + if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1)) + return rv_first; + rv = NULL; + } + + // test CHECKCOMPOUNDPATTERN conditions (allowed forms) + if (rv && + !(scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL || + TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) + rv = NULL; + + // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds) + if (rv && numcheckcpd && scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) + rv = NULL; + + // check non_compound flag in suffix and prefix + if ((rv) && ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, + pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check FORCEUCASE + if (rv && forceucase && (rv) && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = NULL; + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + (is_sug && nosuggest && + TESTAFF(rv->astr, nosuggest, rv->alen)))) + return NULL; + + // pfxappnd = prefix of word+i, or NULL + // calculate syllable number of prefix. + // hungarian convention: when syllable number of prefix is more, + // than 1, the prefix+word counts as two words. + + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(word + i); + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= get_syllable(tmp) + sfxextra; + } + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + + // increment syllable num, if last word has a SYLLABLENUM flag + // and the suffix is beginning `s' + + if (cpdsyllablenum) { + switch (sfxflag) { + case 'c': { + numsyllable += 2; + break; + } + case 'J': { + numsyllable += 1; + break; + } + case 'I': { + if (rv && TESTAFF(rv->astr, 'J', rv->alen)) + numsyllable += 1; + break; + } + } + } + } + + // increment word number, if the second word has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // second word is acceptable, as a word with prefix or/and suffix? + // hungarian conventions: compounding is acceptable, + // when compound forms consist 2 word, otherwise + // the syllable number of root words is 6, or lesser. + if ((rv) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word is a compound word (recursive call) + if (wordnum < maxwordnum) { + rv = compound_check(st.c_str() + i, strlen(st.c_str() + i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + is_sug, info); + + if (rv && numcheckcpd && + ((scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) || + (scpd != 0 && + !cpdpat_check(word, i, rv_first, rv, affixed)))) + rv = NULL; + } else { + rv = NULL; + } + if (rv) { + // forbid compound word, if it is a non compound word with typical + // fault + if (checkcompoundrep || forbiddenword) { + struct hentry* rv2 = NULL; + + if (checkcompoundrep && cpdrep_check(word, len)) + return NULL; + + // check first part + if (strncmp(rv->word, word + i, rv->blen) == 0) { + char r = st[i + rv->blen]; + st[i + rv->blen] = '\0'; + + if (checkcompoundrep && cpdrep_check(st.c_str(), i + rv->blen)) { + st[ + i + rv->blen] = r; + continue; + } + + if (forbiddenword) { + rv2 = lookup(word); + if (!rv2) + rv2 = affix_check(word, len); + if (rv2 && rv2->astr && + TESTAFF(rv2->astr, forbiddenword, rv2->alen) && + (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) { + return NULL; + } + } + st[i + rv->blen] = r; + } + } + return rv_first; + } + } while (striple && !checkedstriple); // end of striple loop + + if (checkedstriple) { + i++; + checkedstriple = 0; + striple = 0; + } + + } // first word is ok condition + + if (soldi != 0) { + i = soldi; + soldi = 0; + len = oldlen; + cmin = oldcmin; + cmax = oldcmax; + } + scpd++; + + } while (!onlycpdrule && simplifiedcpd && + scpd <= numcheckcpd); // end of simplifiedcpd loop + + scpd = 0; + wordnum = oldwordnum; + numsyllable = oldnumsyllable; + + if (soldi != 0) { + i = soldi; + st.assign(word); // XXX add more optim. + soldi = 0; + } else + st[i] = ch; + + } while (numdefcpd && oldwordnum == 0 && + onlycpdrule++ < 1); // end of onlycpd loop + } + + return NULL; +} + +// check if compound word is correctly spelled +// hu_mov_rule = spec. Hungarian rule (XXX) +int AffixMgr::compound_check_morph(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule = 0, + char** result = NULL, + char* partresult = NULL) { + int i; + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + int ok = 0; + + struct hentry* rv = NULL; + struct hentry* rv_first; + std::string st; + char ch; + + int checked_prefix; + char presult[MAXLNLEN]; + + int cmin; + int cmax; + + int onlycpdrule; + char affixed = 0; + hentry** oldwords = words; + + setcminmax(&cmin, &cmax, word, len); + + st.assign(word); + + for (i = cmin; i < cmax; i++) { + // go to end of the UTF-8 character + if (utf8) { + for (; (st[i] & 0xc0) == 0x80; i++) + ; + if (i >= cmax) + return 0; + } + + words = oldwords; + onlycpdrule = (words) ? 1 : 0; + + do { // onlycpdrule loop + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + ch = st[i]; + st[i] = '\0'; + sfx = NULL; + + // FIRST WORD + + affixed = 1; + + *presult = '\0'; + if (partresult) + mystrcat(presult, partresult, MAXLNLEN); + + rv = lookup(st.c_str()); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && !hu_mov_rule && + ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundbegin && !wordnum && !onlycpdrule && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + (compoundmiddle && wordnum && !words && !onlycpdrule && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) || + (numdefcpd && onlycpdrule && + ((!words && !wordnum && + defcpd_check(&words, wnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, rv, rwords, 0))))))) { + rv = rv->next_homonym; + } + + if (rv) + affixed = 0; + + if (rv) { + sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_PART, st.c_str()); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_STEM, + st.c_str()); + } + // store the pointer of the hash entry + // sprintf(presult + strlen(presult), "%c%s%p", MSEP_FLD, + // MORPH_HENTRY, rv); + if (HENTRY_DATA(rv)) { + sprintf(presult + strlen(presult), "%c%s", MSEP_FLD, + HENTRY_DATA2(rv)); + } + } + + if (!rv) { + if (onlycpdrule && strlen(*result) > MAXLNLEN / 10) + break; + if (compoundflag && + !(rv = + prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundflag, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())) || + (compoundend && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = NULL; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundbegin, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundbegin))) || // twofold suffix+compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, + compoundmiddle, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && + (rv = suffix_check_twosfx( + st.c_str(), i, 0, NULL, + compoundmiddle))) || // twofold suffix+compound + (rv = prefix_check(st.c_str(), i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundmiddle)))))) { + // char * p = prefix_check_morph(st, i, 0, compound); + char* p = NULL; + if (compoundflag) + p = affix_check_morph(st.c_str(), i, compoundflag); + if (!p || (*p == '\0')) { + if (p) + free(p); + p = NULL; + if ((wordnum == 0) && compoundbegin) { + p = affix_check_morph(st.c_str(), i, compoundbegin); + } else if ((wordnum > 0) && compoundmiddle) { + p = affix_check_morph(st.c_str(), i, compoundmiddle); + } + } + if (p && (*p != '\0')) { + sprintf(presult + strlen(presult), "%c%s%s%s", MSEP_FLD, MORPH_PART, + st.c_str(), line_uniq_app(&p, MSEP_REC)); + } + if (p) + free(p); + checked_prefix = 1; + } + // else check forbiddenwords + } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, needaffix, rv->alen))) { + st[i] = ch; + continue; + } + + // check non_compound flag in suffix and prefix + if ((rv) && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())))) { + continue; + } + + // check compoundend flag in suffix and prefix + if ((rv) && !checked_prefix && compoundend && !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundend, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + continue; + } + + // check compoundmiddle flag in suffix and prefix + if ((rv) && !checked_prefix && (wordnum == 0) && compoundmiddle && + !hu_mov_rule && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundmiddle, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundmiddle, sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) + continue; + + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // first word is acceptable in compound words? + if (((rv) && + (checked_prefix || (words && words[wnum]) || + (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + ((oldwordnum == 0) && compoundbegin && + TESTAFF(rv->astr, compoundbegin, rv->alen)) || + ((oldwordnum > 0) && compoundmiddle && + TESTAFF(rv->astr, compoundmiddle, rv->alen)) + // LANG_hu section: spec. Hungarian rule + || ((langnum == LANG_hu) && // hu_mov_rule + hu_mov_rule && (TESTAFF(rv->astr, 'F', rv->alen) || + TESTAFF(rv->astr, 'G', rv->alen) || + TESTAFF(rv->astr, 'H', rv->alen))) + // END of LANG_hu section + ) && + !((checkcompoundtriple && !words && // test triple letters + (word[i - 1] == word[i]) && + (((i > 1) && (word[i - 1] == word[i - 2])) || + ((word[i - 1] == word[i + 1])) // may be word[i+1] == '\0' + )) || + ( + // test CHECKCOMPOUNDPATTERN + numcheckcpd && !words && + cpdpat_check(word, i, rv, NULL, affixed)) || + (checkcompoundcase && !words && cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || + ((!rv) && (langnum == LANG_hu) && hu_mov_rule && + (rv = affix_check(st.c_str(), i)) && + (sfx && sfx->getCont() && + (TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) || + TESTAFF(sfx->getCont(), (unsigned short)'%', sfx->getContLen())))) + // END of LANG_hu section + ) { + // LANG_hu section: spec. Hungarian rule + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(st.substr(i)); + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + } + // END of LANG_hu section + + // NEXT WORD(S) + rv_first = rv; + rv = lookup((word + i)); // perhaps without prefix + + // search homonym with compound flag + while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) || + !((compoundflag && !words && + TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && !words && + TESTAFF(rv->astr, compoundend, rv->alen)) || + (numdefcpd && words && + defcpd_check(&words, wnum + 1, rv, NULL, 1))))) { + rv = rv->next_homonym; + } + + if (rv && words && words[wnum + 1]) { + mystrcat(*result, presult, MAXLNLEN); + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_PART, MAXLNLEN); + mystrcat(*result, word + i, MAXLNLEN); + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_STEM, MAXLNLEN); + mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(*result + strlen(*result), " %s%p", + // MORPH_HENTRY, rv); + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + } + mystrcat(*result, "\n", MAXLNLEN); + return 0; + } + + oldnumsyllable2 = numsyllable; + oldwordnum2 = wordnum; + + // LANG_hu section: spec. Hungarian rule + if ((rv) && (langnum == LANG_hu) && + (TESTAFF(rv->astr, 'I', rv->alen)) && + !(TESTAFF(rv->astr, 'J', rv->alen))) { + numsyllable--; + } + // END of LANG_hu section + // increment word number, if the second root has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) { + st[i] = ch; + continue; + } + + // second word is acceptable, as a root? + // hungarian conventions: compounding is acceptable, + // when compound forms consist of 2 words, or if more, + // then the syllable number of root words must be 6, or lesser. + if ((rv) && + ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) || + (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && + (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <= + cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + // bad compound word + mystrcat(*result, presult, MAXLNLEN); + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_PART, MAXLNLEN); + mystrcat(*result, word + i, MAXLNLEN); + + if (HENTRY_DATA(rv)) { + if (complexprefixes) + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, MORPH_STEM, MAXLNLEN); + mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(*result + strlen(*result), " + // %s%p", MORPH_HENTRY, rv); + if (!complexprefixes) { + mystrcat(*result, " ", MAXLNLEN); + mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN); + } + } + mystrcat(*result, "\n", MAXLNLEN); + ok = 1; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = NULL; + sfxflag = FLAG_NULL; + + if (compoundflag && !onlycpdrule) + rv = affix_check((word + i), strlen(word + i), compoundflag); + else + rv = NULL; + + if (!rv && compoundend && !onlycpdrule) { + sfx = NULL; + pfx = NULL; + rv = affix_check((word + i), strlen(word + i), compoundend); + } + + if (!rv && numdefcpd && words) { + rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END); + if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) { + char* m = NULL; + if (compoundflag) + m = affix_check_morph((word + i), strlen(word + i), compoundflag); + if ((!m || *m == '\0') && compoundend) { + if (m) + free(m); + m = affix_check_morph((word + i), strlen(word + i), compoundend); + } + mystrcat(*result, presult, MAXLNLEN); + if (m || (*m != '\0')) { + char m2[MAXLNLEN]; + sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i, + line_uniq_app(&m, MSEP_REC)); + mystrcat(*result, m2, MAXLNLEN); + } + if (m) + free(m); + mystrcat(*result, "\n", MAXLNLEN); + ok = 1; + } + } + + // check non_compound flag in suffix and prefix + if ((rv) && + ((pfx && pfx->getCont() && + TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) || + (sfx && sfx->getCont() && + TESTAFF(sfx->getCont(), compoundforbidflag, + sfx->getContLen())))) { + rv = NULL; + } + + // check forbiddenwords + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, forbiddenword, rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen)) && + (!TESTAFF(rv->astr, needaffix, rv->alen))) { + st[i] = ch; + continue; + } + + if (langnum == LANG_hu) { + // calculate syllable number of the word + numsyllable += get_syllable(word + i); + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= get_syllable(tmp) + sfxextra; + } + + // + 1 word, if syllable number of the prefix > 1 (hungarian + // convention) + if (pfx && (get_syllable(pfx->getKey()) > 1)) + wordnum++; + + // increment syllable num, if last word has a SYLLABLENUM flag + // and the suffix is beginning `s' + + if (cpdsyllablenum) { + switch (sfxflag) { + case 'c': { + numsyllable += 2; + break; + } + case 'J': { + numsyllable += 1; + break; + } + case 'I': { + if (rv && TESTAFF(rv->astr, 'J', rv->alen)) + numsyllable += 1; + break; + } + } + } + } + + // increment word number, if the second word has a compoundroot flag + if ((rv) && (compoundroot) && + (TESTAFF(rv->astr, compoundroot, rv->alen))) { + wordnum++; + } + // second word is acceptable, as a word with prefix or/and suffix? + // hungarian conventions: compounding is acceptable, + // when compound forms consist 2 word, otherwise + // the syllable number of root words is 6, or lesser. + if ((rv) && + (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || + ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) && + ((!checkcompounddup || (rv != rv_first)))) { + char* m = NULL; + if (compoundflag) + m = affix_check_morph((word + i), strlen(word + i), compoundflag); + if ((!m || *m == '\0') && compoundend) { + if (m) + free(m); + m = affix_check_morph((word + i), strlen(word + i), compoundend); + } + mystrcat(*result, presult, MAXLNLEN); + if (m && (*m != '\0')) { + char m2[MAXLNLEN]; + sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i, + line_uniq_app(&m, MSEP_REC)); + mystrcat(*result, m2, MAXLNLEN); + } + if (m) + free(m); + if (strlen(*result) + 1 < MAXLNLEN) + sprintf(*result + strlen(*result), "%c", MSEP_REC); + ok = 1; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word is a compound word (recursive call) + if ((wordnum < maxwordnum) && (ok == 0)) { + compound_check_morph((word + i), strlen(word + i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + result, presult); + } else { + rv = NULL; + } + } + st[i] = ch; + wordnum = oldwordnum; + numsyllable = oldnumsyllable; + + } while (numdefcpd && oldwordnum == 0 && + onlycpdrule++ < 1); // end of onlycpd loop + } + return 0; +} + + +// return 1 if s1 (reversed) is a leading subset of end of s2 +/* inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int + len) + { + while ((len > 0) && *s1 && (*s1 == *end_of_s2)) { + s1++; + end_of_s2--; + len--; + } + return (*s1 == '\0'); + } + */ + +inline int AffixMgr::isRevSubset(const char* s1, + const char* end_of_s2, + int len) { + while ((len > 0) && (*s1 != '\0') && ((*s1 == *end_of_s2) || (*s1 == '.'))) { + s1++; + end_of_s2--; + len--; + } + return (*s1 == '\0'); +} + +// check word for suffixes + +struct hentry* AffixMgr::suffix_check(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + struct hentry* rv = NULL; + PfxEntry* ep = ppfx; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + + while (se) { + if (!cclass || se->getCont()) { + // suffixes are not allowed in beginning of compounds + if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (se->getCont() && compoundpermitflag && + TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!se->getCont() || + !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (se->getCont() && + (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && + // fogemorpheme + (in_compound || + !(se->getCont() && + (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) && + // needaffix on prefix or first suffix + (cclass || + !(se->getCont() && + TESTAFF(se->getCont(), needaffix, se->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) { + rv = se->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns, + (FLAG)cclass, needflag, + (in_compound ? 0 : onlyincompound)); + if (rv) { + sfx = se; // BUG: sfx not stateless + return rv; + } + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + // suffixes are not allowed in beginning of compounds + if ((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (sptr->getCont() && compoundpermitflag && + TESTAFF(sptr->getCont(), compoundpermitflag, + sptr->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!sptr->getCont() || + !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (sptr->getCont() && + (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && + // fogemorpheme + (in_compound || + !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, + sptr->getContLen()))))) && + // needaffix on prefix or first suffix + (cclass || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) + if (in_compound != IN_CPD_END || ppfx || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) { + rv = sptr->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns, + cclass, needflag, + (in_compound ? 0 : onlyincompound)); + if (rv) { + sfx = sptr; // BUG: sfx not stateless + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + // LANG_hu section: spec. Hungarian rule + else if (langnum == LANG_hu && sptr->getKeyLen() && + sptr->getKey()[0] == 'i' && sptr->getKey()[1] != 'y' && + sptr->getKey()[1] != 't') { + sfxextra = 1; + } + // END of LANG_hu section + return rv; + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + return NULL; +} + +// check word for two-level suffixes + +struct hentry* AffixMgr::suffix_check_twosfx(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag) { + struct hentry* rv = NULL; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (contclasses[se->getFlag()]) { + rv = se->check_twosfx(word, len, sfxopts, ppfx, needflag); + if (rv) + return rv; + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + rv = sptr->check_twosfx(word, len, sfxopts, ppfx, needflag); + if (rv) { + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + return rv; + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + return NULL; +} + +char* AffixMgr::suffix_check_twosfx_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag) { + std::string result; + std::string result2; + std::string result3; + + char* st; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (contclasses[se->getFlag()]) { + st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); + if (st) { + if (ppfx) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.append(" "); + } else + debugflag(result, ppfx->getFlag()); + } + result.append(st); + free(st); + if (se->getMorph()) { + result.append(" "); + result.append(se->getMorph()); + } else + debugflag(result, se->getFlag()); + result.append("\n"); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag); + if (st) { + sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless + if (!sptr->getCont()) + sfxappnd = sptr->getKey(); // BUG: sfxappnd not stateless + result2.assign(st); + free(st); + + result3.clear(); + + if (sptr->getMorph()) { + result3.append(" "); + result3.append(sptr->getMorph()); + } else + debugflag(result3, sptr->getFlag()); + strlinecat(result2, result3); + result2.append("\n"); + result.append(result2); + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + if (!result.empty()) + return mystrdup(result.c_str()); + + return NULL; +} + +char* AffixMgr::suffix_check_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + char result[MAXLNLEN]; + + struct hentry* rv = NULL; + + result[0] = '\0'; + + PfxEntry* ep = ppfx; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (!cclass || se->getCont()) { + // suffixes are not allowed in beginning of compounds + if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (se->getCont() && compoundpermitflag && + TESTAFF(se->getCont(), compoundpermitflag, se->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!se->getCont() || + !(TESTAFF(se->getCont(), circumfix, se->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (se->getCont() && + (TESTAFF(se->getCont(), circumfix, se->getContLen()))))) && + // fogemorpheme + (in_compound || + !((se->getCont() && + (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) && + // needaffix on prefix or first suffix + (cclass || + !(se->getCont() && + TESTAFF(se->getCont(), needaffix, se->getContLen())) || + (ppfx && + !((ep->getCont()) && + TESTAFF(ep->getCont(), needaffix, ep->getContLen())))))) + rv = se->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass, + needflag); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(result + strlen(result), " %s%p", MORPH_HENTRY, + // rv); + + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + if (se->getMorph()) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, se->getMorph(), MAXLNLEN); + } else + debugflag(result, se->getFlag()); + mystrcat(result, "\n", MAXLNLEN); + rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return NULL; // FULLSTRIP + unsigned char sp = *((const unsigned char*)(word + len - 1)); + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word + len - 1, len)) { + // suffixes are not allowed in beginning of compounds + if (((((in_compound != IN_CPD_BEGIN)) || // && !cclass + // except when signed with compoundpermitflag flag + (sptr->getCont() && compoundpermitflag && + TESTAFF(sptr->getCont(), compoundpermitflag, + sptr->getContLen()))) && + (!circumfix || + // no circumfix flag in prefix and suffix + ((!ppfx || !(ep->getCont()) || + !TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (!sptr->getCont() || + !(TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())))) || + // circumfix flag in prefix AND suffix + ((ppfx && (ep->getCont()) && + TESTAFF(ep->getCont(), circumfix, ep->getContLen())) && + (sptr->getCont() && + (TESTAFF(sptr->getCont(), circumfix, sptr->getContLen()))))) && + // fogemorpheme + (in_compound || + !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, + sptr->getContLen()))))) && + // needaffix on first suffix + (cclass || + !(sptr->getCont() && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen()))))) + rv = sptr->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass, + needflag); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + mystrcat(result, ppfx->getMorph(), MAXLNLEN); + mystrcat(result, " ", MAXLNLEN); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, HENTRY_WORD(rv), MAXLNLEN); + } + // store the pointer of the hash entry + // sprintf(result + strlen(result), " %s%p", + // MORPH_HENTRY, rv); + + if (!complexprefixes && HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + + if (sptr->getMorph()) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, sptr->getMorph(), MAXLNLEN); + } else + debugflag(result, sptr->getFlag()); + mystrcat(result, "\n", MAXLNLEN); + rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + if (*result) + return mystrdup(result); + return NULL; +} + +// check if word with affixes is correctly spelled +struct hentry* AffixMgr::affix_check(const char* word, + int len, + const FLAG needflag, + char in_compound) { + struct hentry* rv = NULL; + + // check all prefixes (also crossed with suffixes if allowed) + rv = prefix_check(word, len, in_compound, needflag); + if (rv) + return rv; + + // if still not found check all suffixes + rv = suffix_check(word, len, 0, NULL, NULL, 0, NULL, FLAG_NULL, needflag, + in_compound); + + if (havecontclass) { + sfx = NULL; + pfx = NULL; + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = suffix_check_twosfx(word, len, 0, NULL, needflag); + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag); + } + + return rv; +} + +// check if word with affixes is correctly spelled +char* AffixMgr::affix_check_morph(const char* word, + int len, + const FLAG needflag, + char in_compound) { + char result[MAXLNLEN]; + char* st = NULL; + + *result = '\0'; + + // check all prefixes (also crossed with suffixes if allowed) + st = prefix_check_morph(word, len, in_compound); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + // if still not found check all suffixes + st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + if (havecontclass) { + sfx = NULL; + pfx = NULL; + // if still not found check all two-level suffixes + st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + // if still not found check all two-level suffixes + st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + } + + return mystrdup(result); +} + +char* AffixMgr::morphgen(const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* morph, + const char* targetmorph, + int level) { + // handle suffixes + if (!morph) + return NULL; + + // check substandard flag + if (TESTAFF(ap, substandard, al)) + return NULL; + + if (morphcmp(morph, targetmorph) == 0) + return mystrdup(ts); + + size_t stemmorphcatpos; + std::string mymorph; + + // use input suffix fields, if exist + if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) { + mymorph.assign(morph); + mymorph.append(" "); + stemmorphcatpos = mymorph.size(); + } else { + stemmorphcatpos = std::string::npos; + } + + for (int i = 0; i < al; i++) { + const unsigned char c = (unsigned char)(ap[i] & 0x00FF); + SfxEntry* sptr = sFlag[c]; + while (sptr) { + if (sptr->getFlag() == ap[i] && sptr->getMorph() && + ((sptr->getContLen() == 0) || + // don't generate forms with substandard affixes + !TESTAFF(sptr->getCont(), substandard, sptr->getContLen()))) { + const char* stemmorph; + if (stemmorphcatpos != std::string::npos) { + mymorph.replace(stemmorphcatpos, std::string::npos, sptr->getMorph()); + stemmorph = mymorph.c_str(); + } else { + stemmorph = sptr->getMorph(); + } + + int cmp = morphcmp(stemmorph, targetmorph); + + if (cmp == 0) { + char* newword = sptr->add(ts, wl); + if (newword) { + hentry* check = pHMgr->lookup(newword); // XXX extra dic + if (!check || !check->astr || + !(TESTAFF(check->astr, forbiddenword, check->alen) || + TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) { + return newword; + } + free(newword); + } + } + + // recursive call for secondary suffixes + if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) && + // (get_sfxcount(stemmorph) < targetcount) && + !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) { + char* newword = sptr->add(ts, wl); + if (newword) { + char* newword2 = + morphgen(newword, strlen(newword), sptr->getCont(), + sptr->getContLen(), stemmorph, targetmorph, 1); + + if (newword2) { + free(newword); + return newword2; + } + free(newword); + newword = NULL; + } + } + } + sptr = sptr->getFlgNxt(); + } + } + return NULL; +} + +int AffixMgr::expand_rootword(struct guessword* wlst, + int maxn, + const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* bad, + int badl, + const char* phon) { + int nh = 0; + // first add root word to list + if ((nh < maxn) && + !(al && ((needaffix && TESTAFF(ap, needaffix, al)) || + (onlyincompound && TESTAFF(ap, onlyincompound, al))))) { + wlst[nh].word = mystrdup(ts); + if (!wlst[nh].word) + return 0; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = NULL; + nh++; + // add special phonetic version + if (phon && (nh < maxn)) { + wlst[nh].word = mystrdup(phon); + if (!wlst[nh].word) + return nh - 1; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = mystrdup(ts); + if (!wlst[nh].orig) + return nh - 1; + nh++; + } + } + + // handle suffixes + for (int i = 0; i < al; i++) { + const unsigned char c = (unsigned char)(ap[i] & 0x00FF); + SfxEntry* sptr = sFlag[c]; + while (sptr) { + if ((sptr->getFlag() == ap[i]) && + (!sptr->getKeyLen() || + ((badl > sptr->getKeyLen()) && + (strcmp(sptr->getAffix(), bad + badl - sptr->getKeyLen()) == 0))) && + // check needaffix flag + !(sptr->getCont() && + ((needaffix && + TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) || + (circumfix && + TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) || + (onlyincompound && + TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) { + char* newword = sptr->add(ts, wl); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = sptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + // add special phonetic version + if (phon && (nh < maxn)) { + std::string prefix(phon); + std::string key(sptr->getKey()); + reverseword(key); + prefix.append(key); + wlst[nh].word = mystrdup(prefix.c_str()); + if (!wlst[nh].word) + return nh - 1; + wlst[nh].allow = (1 == 0); + wlst[nh].orig = mystrdup(newword); + if (!wlst[nh].orig) + return nh - 1; + nh++; + } + } else { + free(newword); + } + } + } + sptr = sptr->getFlgNxt(); + } + } + + int n = nh; + + // handle cross products of prefixes and suffixes + for (int j = 1; j < n; j++) + if (wlst[j].allow) { + for (int k = 0; k < al; k++) { + const unsigned char c = (unsigned char)(ap[k] & 0x00FF); + PfxEntry* cptr = pFlag[c]; + while (cptr) { + if ((cptr->getFlag() == ap[k]) && cptr->allowCross() && + (!cptr->getKeyLen() || + ((badl > cptr->getKeyLen()) && + (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) { + int l1 = strlen(wlst[j].word); + char* newword = cptr->add(wlst[j].word, l1); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = cptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + } else { + free(newword); + } + } + } + cptr = cptr->getFlgNxt(); + } + } + } + + // now handle pure prefixes + for (int m = 0; m < al; m++) { + const unsigned char c = (unsigned char)(ap[m] & 0x00FF); + PfxEntry* ptr = pFlag[c]; + while (ptr) { + if ((ptr->getFlag() == ap[m]) && + (!ptr->getKeyLen() || + ((badl > ptr->getKeyLen()) && + (strncmp(ptr->getKey(), bad, ptr->getKeyLen()) == 0))) && + // check needaffix flag + !(ptr->getCont() && + ((needaffix && + TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) || + (circumfix && + TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) || + (onlyincompound && + TESTAFF(ptr->getCont(), onlyincompound, ptr->getContLen()))))) { + char* newword = ptr->add(ts, wl); + if (newword) { + if (nh < maxn) { + wlst[nh].word = newword; + wlst[nh].allow = ptr->allowCross(); + wlst[nh].orig = NULL; + nh++; + } else { + free(newword); + } + } + } + ptr = ptr->getFlgNxt(); + } + } + + return nh; +} + +// return length of replacing table +int AffixMgr::get_numrep() const { + return numrep; +} + +// return replacing table +struct replentry* AffixMgr::get_reptable() const { + if (!reptable) + return NULL; + return reptable; +} + +// return iconv table +RepList* AffixMgr::get_iconvtable() const { + if (!iconvtable) + return NULL; + return iconvtable; +} + +// return oconv table +RepList* AffixMgr::get_oconvtable() const { + if (!oconvtable) + return NULL; + return oconvtable; +} + +// return replacing table +struct phonetable* AffixMgr::get_phonetable() const { + if (!phone) + return NULL; + return phone; +} + +// return length of character map table +int AffixMgr::get_nummap() const { + return nummap; +} + +// return character map table +struct mapentry* AffixMgr::get_maptable() const { + if (!maptable) + return NULL; + return maptable; +} + +// return length of word break table +int AffixMgr::get_numbreak() const { + return numbreak; +} + +// return character map table +char** AffixMgr::get_breaktable() const { + if (!breaktable) + return NULL; + return breaktable; +} + +// return text encoding of dictionary +char* AffixMgr::get_encoding() { + if (!encoding) + encoding = mystrdup(SPELL_ENCODING); + return mystrdup(encoding); +} + +// return text encoding of dictionary +int AffixMgr::get_langnum() const { + return langnum; +} + +// return double prefix option +int AffixMgr::get_complexprefixes() const { + return complexprefixes; +} + +// return FULLSTRIP option +int AffixMgr::get_fullstrip() const { + return fullstrip; +} + +FLAG AffixMgr::get_keepcase() const { + return keepcase; +} + +FLAG AffixMgr::get_forceucase() const { + return forceucase; +} + +FLAG AffixMgr::get_warn() const { + return warn; +} + +int AffixMgr::get_forbidwarn() const { + return forbidwarn; +} + +int AffixMgr::get_checksharps() const { + return checksharps; +} + +char* AffixMgr::encode_flag(unsigned short aflag) const { + return pHMgr->encode_flag(aflag); +} + +// return the preferred ignore string for suggestions +char* AffixMgr::get_ignore() const { + if (!ignorechars) + return NULL; + return ignorechars; +} + +// return the preferred ignore string for suggestions +const std::vector<w_char>& AffixMgr::get_ignore_utf16() const { + return ignorechars_utf16; +} + +// return the keyboard string for suggestions +char* AffixMgr::get_key_string() { + if (!keystring) + keystring = mystrdup(SPELL_KEYSTRING); + return mystrdup(keystring); +} + +// return the preferred try string for suggestions +char* AffixMgr::get_try_string() const { + if (!trystring) + return NULL; + return mystrdup(trystring); +} + +// return the preferred try string for suggestions +const char* AffixMgr::get_wordchars() const { + return wordchars; +} + +const std::vector<w_char>& AffixMgr::get_wordchars_utf16() const { + return wordchars_utf16; +} + +// is there compounding? +int AffixMgr::get_compound() const { + return compoundflag || compoundbegin || numdefcpd; +} + +// return the compound words control flag +FLAG AffixMgr::get_compoundflag() const { + return compoundflag; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_forbiddenword() const { + return forbiddenword; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_nosuggest() const { + return nosuggest; +} + +// return the forbidden words control flag +FLAG AffixMgr::get_nongramsuggest() const { + return nongramsuggest; +} + +// return the forbidden words flag modify flag +FLAG AffixMgr::get_needaffix() const { + return needaffix; +} + +// return the onlyincompound flag +FLAG AffixMgr::get_onlyincompound() const { + return onlyincompound; +} + +// return the compound word signal flag +FLAG AffixMgr::get_compoundroot() const { + return compoundroot; +} + +// return the compound begin signal flag +FLAG AffixMgr::get_compoundbegin() const { + return compoundbegin; +} + +// return the value of checknum +int AffixMgr::get_checknum() const { + return checknum; +} + +// return the value of prefix +const char* AffixMgr::get_prefix() const { + if (pfx) + return pfx->getKey(); + return NULL; +} + +// return the value of suffix +const char* AffixMgr::get_suffix() const { + return sfxappnd; +} + +// return the value of suffix +const char* AffixMgr::get_version() const { + return version; +} + +// return lemma_present flag +FLAG AffixMgr::get_lemma_present() const { + return lemma_present; +} + +// utility method to look up root words in hash table +struct hentry* AffixMgr::lookup(const char* word) { + int i; + struct hentry* he = NULL; + for (i = 0; i < *maxdic && !he; i++) { + he = (alldic[i])->lookup(word); + } + return he; +} + +// return the value of suffix +int AffixMgr::have_contclass() const { + return havecontclass; +} + +// return utf8 +int AffixMgr::get_utf8() const { + return utf8; +} + +int AffixMgr::get_maxngramsugs(void) const { + return maxngramsugs; +} + +int AffixMgr::get_maxcpdsugs(void) const { + return maxcpdsugs; +} + +int AffixMgr::get_maxdiff(void) const { + return maxdiff; +} + +int AffixMgr::get_onlymaxdiff(void) const { + return onlymaxdiff; +} + +// return nosplitsugs +int AffixMgr::get_nosplitsugs(void) const { + return nosplitsugs; +} + +// return sugswithdots +int AffixMgr::get_sugswithdots(void) const { + return sugswithdots; +} + +/* parse flag */ +int AffixMgr::parse_flag(char* line, unsigned short* out, FileMgr* af) { + char* s = NULL; + if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix file parameter\n", + af->getlinenum()); + return 1; + } + if (parse_string(line, &s, af->getlinenum())) + return 1; + *out = pHMgr->decode_flag(s); + free(s); + return 0; +} + +/* parse num */ +int AffixMgr::parse_num(char* line, int* out, FileMgr* af) { + char* s = NULL; + if (*out != -1) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix file parameter\n", + af->getlinenum()); + return 1; + } + if (parse_string(line, &s, af->getlinenum())) + return 1; + *out = atoi(s); + free(s); + return 0; +} + +/* parse in the max syllablecount of compound words and */ +int AffixMgr::parse_cpdsyllable(char* line, FileMgr* af) { + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + cpdmaxsyllable = atoi(piece); + np++; + break; + } + case 2: { + if (!utf8) { + cpdvowels = mystrdup(piece); + } else { + std::vector<w_char> w; + u8_u16(w, piece); + if (!w.empty()) { + std::sort(w.begin(), w.end()); + cpdvowels_utf16 = (w_char*)malloc(w.size() * sizeof(w_char)); + if (!cpdvowels_utf16) + return 1; + memcpy(cpdvowels_utf16, &w[0], w.size()); + } + cpdvowels_utf16_len = w.size(); + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np < 2) { + HUNSPELL_WARNING(stderr, + "error: line %d: missing compoundsyllable information\n", + af->getlinenum()); + return 1; + } + if (np == 2) + cpdvowels = mystrdup("aeiouAEIOU"); + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_reptable(char* line, FileMgr* af) { + if (numrep != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numrep = atoi(piece); + if (numrep < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", + af->getlinenum()); + return 1; + } + reptable = (replentry*)malloc(numrep * sizeof(struct replentry)); + if (!reptable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numrep lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numrep; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + reptable[j].pattern = NULL; + reptable[j].pattern2 = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "REP", 3) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numrep = 0; + return 1; + } + break; + } + case 1: { + if (*piece == '^') + reptable[j].start = true; + else + reptable[j].start = false; + reptable[j].pattern = + mystrrep(mystrdup(piece + int(reptable[j].start)), "_", " "); + int lr = strlen(reptable[j].pattern) - 1; + if (reptable[j].pattern[lr] == '$') { + reptable[j].end = true; + reptable[j].pattern[lr] = '\0'; + } else + reptable[j].end = false; + break; + } + case 2: { + reptable[j].pattern2 = mystrrep(mystrdup(piece), "_", " "); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numrep = 0; + return 1; + } + } + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_convtable(char* line, + FileMgr* af, + RepList** rl, + const char* keyword) { + if (*rl) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + int numrl = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numrl = atoi(piece); + if (numrl < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", + af->getlinenum()); + return 1; + } + *rl = new RepList(numrl); + if (!*rl) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the num lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numrl; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + char* pattern = NULL; + char* pattern2 = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, keyword, strlen(keyword)) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + delete *rl; + *rl = NULL; + return 1; + } + break; + } + case 1: { + pattern = mystrrep(mystrdup(piece), "_", " "); + break; + } + case 2: { + pattern2 = mystrrep(mystrdup(piece), "_", " "); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!pattern || !pattern2) { + if (pattern) + free(pattern); + if (pattern2) + free(pattern2); + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + (*rl)->add(pattern, pattern2); + } + return 0; +} + +/* parse in the typical fault correcting table */ +int AffixMgr::parse_phonetable(char* line, FileMgr* af) { + if (phone) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + phone = (phonetable*)malloc(sizeof(struct phonetable)); + if (!phone) + return 1; + phone->num = atoi(piece); + phone->rules = NULL; + phone->utf8 = (char)utf8; + if (phone->num < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + phone->rules = (char**)malloc(2 * (phone->num + 1) * sizeof(char*)); + if (!phone->rules) { + free(phone); + phone = NULL; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the phone->num lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < phone->num; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + phone->rules[j * 2] = NULL; + phone->rules[j * 2 + 1] = NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "PHONE", 5) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + phone->num = 0; + return 1; + } + break; + } + case 1: { + phone->rules[j * 2] = mystrrep(mystrdup(piece), "_", ""); + break; + } + case 2: { + phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece), "_", ""); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + phone->num = 0; + return 1; + } + } + phone->rules[phone->num * 2] = mystrdup(""); + phone->rules[phone->num * 2 + 1] = mystrdup(""); + init_phonet_hash(*phone); + return 0; +} + +/* parse in the checkcompoundpattern table */ +int AffixMgr::parse_checkcpdtable(char* line, FileMgr* af) { + if (numcheckcpd != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numcheckcpd = atoi(piece); + if (numcheckcpd < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + checkcpdtable = + (patentry*)malloc(numcheckcpd * sizeof(struct patentry)); + if (!checkcpdtable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numcheckcpd lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numcheckcpd; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + checkcpdtable[j].pattern = NULL; + checkcpdtable[j].pattern2 = NULL; + checkcpdtable[j].pattern3 = NULL; + checkcpdtable[j].cond = FLAG_NULL; + checkcpdtable[j].cond2 = FLAG_NULL; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "CHECKCOMPOUNDPATTERN", 20) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numcheckcpd = 0; + return 1; + } + break; + } + case 1: { + checkcpdtable[j].pattern = mystrdup(piece); + char* p = strchr(checkcpdtable[j].pattern, '/'); + if (p) { + *p = '\0'; + checkcpdtable[j].cond = pHMgr->decode_flag(p + 1); + } + break; + } + case 2: { + checkcpdtable[j].pattern2 = mystrdup(piece); + char* p = strchr(checkcpdtable[j].pattern2, '/'); + if (p) { + *p = '\0'; + checkcpdtable[j].cond2 = pHMgr->decode_flag(p + 1); + } + break; + } + case 3: { + checkcpdtable[j].pattern3 = mystrdup(piece); + simplifiedcpd = 1; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if ((!(checkcpdtable[j].pattern)) || (!(checkcpdtable[j].pattern2))) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numcheckcpd = 0; + return 1; + } + } + return 0; +} + +/* parse in the compound rule table */ +int AffixMgr::parse_defcpdtable(char* line, FileMgr* af) { + if (numdefcpd != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numdefcpd = atoi(piece); + if (numdefcpd < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + defcpdtable = (flagentry*)malloc(numdefcpd * sizeof(flagentry)); + if (!defcpdtable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numdefcpd lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numdefcpd; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + defcpdtable[j].def = NULL; + defcpdtable[j].len = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "COMPOUNDRULE", 12) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numdefcpd = 0; + return 1; + } + break; + } + case 1: { // handle parenthesized flags + if (strchr(piece, '(')) { + defcpdtable[j].def = (FLAG*)malloc(strlen(piece) * sizeof(FLAG)); + defcpdtable[j].len = 0; + int end = 0; + FLAG* conv; + while (!end) { + char* par = piece + 1; + while (*par != '(' && *par != ')' && *par != '\0') + par++; + if (*par == '\0') + end = 1; + else + *par = '\0'; + if (*piece == '(') + piece++; + if (*piece == '*' || *piece == '?') { + defcpdtable[j].def[defcpdtable[j].len++] = (FLAG)*piece; + } else if (*piece != '\0') { + int l = pHMgr->decode_flags(&conv, piece, af); + for (int k = 0; k < l; k++) + defcpdtable[j].def[defcpdtable[j].len++] = conv[k]; + free(conv); + } + piece = par + 1; + } + } else { + defcpdtable[j].len = + pHMgr->decode_flags(&(defcpdtable[j].def), piece, af); + } + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!defcpdtable[j].len) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numdefcpd = 0; + return 1; + } + } + return 0; +} + +/* parse in the character map table */ +int AffixMgr::parse_maptable(char* line, FileMgr* af) { + if (nummap != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + nummap = atoi(piece); + if (nummap < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + maptable = (mapentry*)malloc(nummap * sizeof(struct mapentry)); + if (!maptable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the nummap lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < nummap; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + maptable[j].set = NULL; + maptable[j].len = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "MAP", 3) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + nummap = 0; + return 1; + } + break; + } + case 1: { + int setn = 0; + maptable[j].len = strlen(piece); + maptable[j].set = (char**)malloc(maptable[j].len * sizeof(char*)); + if (!maptable[j].set) + return 1; + for (int k = 0; k < maptable[j].len; k++) { + int chl = 1; + int chb = k; + if (piece[k] == '(') { + char* parpos = strchr(piece + k, ')'); + if (parpos != NULL) { + chb = k + 1; + chl = (int)(parpos - piece) - k - 1; + k = k + chl + 1; + } + } else { + if (utf8 && (piece[k] & 0xc0) == 0xc0) { + for (k++; utf8 && (piece[k] & 0xc0) == 0x80; k++) + ; + chl = k - chb; + k--; + } + } + maptable[j].set[setn] = (char*)malloc(chl + 1); + if (!maptable[j].set[setn]) + return 1; + strncpy(maptable[j].set[setn], piece + chb, chl); + maptable[j].set[setn][chl] = '\0'; + setn++; + } + maptable[j].len = setn; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!maptable[j].set || !maptable[j].len) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + nummap = 0; + return 1; + } + } + return 0; +} + +/* parse in the word breakpoint table */ +int AffixMgr::parse_breaktable(char* line, FileMgr* af) { + if (numbreak > -1) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numbreak = atoi(piece); + if (numbreak < 0) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + if (numbreak == 0) + return 0; + breaktable = (char**)malloc(numbreak * sizeof(char*)); + if (!breaktable) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numbreak lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numbreak; j++) { + if (!(nl = af->getline())) + return 1; + mychomp(nl); + tp = nl; + i = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "BREAK", 5) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numbreak = 0; + return 1; + } + break; + } + case 1: { + breaktable[j] = mystrdup(piece); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!breaktable) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numbreak = 0; + return 1; + } + } + return 0; +} + +void AffixMgr::reverse_condition(std::string& piece) { + if (piece.empty()) + return; + + int neg = 0; + for (std::string::reverse_iterator k = piece.rbegin(); k != piece.rend(); ++k) { + switch (*k) { + case '[': { + if (neg) + *(k - 1) = '['; + else + *k = ']'; + break; + } + case ']': { + *k = '['; + if (neg) + *(k - 1) = '^'; + neg = 0; + break; + } + case '^': { + if (*(k - 1) == ']') + neg = 1; + else + *(k - 1) = *k; + break; + } + default: { + if (neg) + *(k - 1) = *k; + } + } + } +} + +int AffixMgr::parse_affix(char* line, + const char at, + FileMgr* af, + char* dupflags) { + int numents = 0; // number of affentry structures to parse + + unsigned short aflag = 0; // affix char identifier + + char ff = 0; + std::vector<affentry> affentries; + + char* tp = line; + char* nl = line; + char* piece; + int i = 0; + +// checking lines with bad syntax +#ifdef DEBUG + int basefieldnum = 0; +#endif + + // split affix header line into pieces + + int np = 0; + + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + // piece 1 - is type of affix + case 0: { + np++; + break; + } + + // piece 2 - is affix char + case 1: { + np++; + aflag = pHMgr->decode_flag(piece); + if (((at == 'S') && (dupflags[aflag] & dupSFX)) || + ((at == 'P') && (dupflags[aflag] & dupPFX))) { + HUNSPELL_WARNING( + stderr, + "error: line %d: multiple definitions of an affix flag\n", + af->getlinenum()); + // return 1; XXX permissive mode for bad dictionaries + } + dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX); + break; + } + // piece 3 - is cross product indicator + case 2: { + np++; + if (*piece == 'Y') + ff = aeXPRODUCT; + break; + } + + // piece 4 - is number of affentries + case 3: { + np++; + numents = atoi(piece); + if ((numents <= 0) || ((std::numeric_limits<size_t>::max() / + sizeof(struct affentry)) < static_cast<size_t>(numents))) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + free(err); + } + return 1; + } + affentries.resize(numents); + affentries[0].opts = ff; + if (utf8) + affentries[0].opts += aeUTF8; + if (pHMgr->is_aliasf()) + affentries[0].opts += aeALIASF; + if (pHMgr->is_aliasm()) + affentries[0].opts += aeALIASM; + affentries[0].aflag = aflag; + } + + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + // check to make sure we parsed enough pieces + if (np != 4) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + free(err); + } + return 1; + } + + // now parse numents affentries for this affix + std::vector<affentry>::iterator start = affentries.begin(); + std::vector<affentry>::iterator end = affentries.end(); + for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + np = 0; + + // split line into pieces + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + // piece 1 - is type + case 0: { + np++; + if (entry != start) + entry->opts = start->opts & + (char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM); + break; + } + + // piece 2 - is affix char + case 1: { + np++; + if (pHMgr->decode_flag(piece) != aflag) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, + "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err); + free(err); + } + return 1; + } + + if (entry != start) + entry->aflag = start->aflag; + break; + } + + // piece 3 - is string to strip or 0 for null + case 2: { + np++; + entry->strip = piece; + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->strip); + else + reverseword(entry->strip); + } + if (entry->strip.compare("0") == 0) { + entry->strip.clear(); + } + break; + } + + // piece 4 - is affix string or 0 for null + case 3: { + char* dash; + entry->morphcode = NULL; + entry->contclass = NULL; + entry->contclasslen = 0; + np++; + dash = strchr(piece, '/'); + if (dash) { + *dash = '\0'; + + entry->appnd = piece; + + if (ignorechars) { + if (utf8) { + remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); + } else { + remove_ignored_chars(entry->appnd, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->appnd); + else + reverseword(entry->appnd); + } + + if (pHMgr->is_aliasf()) { + int index = atoi(dash + 1); + entry->contclasslen = (unsigned short)pHMgr->get_aliasf( + index, &(entry->contclass), af); + if (!entry->contclasslen) + HUNSPELL_WARNING(stderr, + "error: bad affix flag alias: \"%s\"\n", + dash + 1); + } else { + entry->contclasslen = (unsigned short)pHMgr->decode_flags( + &(entry->contclass), dash + 1, af); + std::sort(entry->contclass, entry->contclass + entry->contclasslen); + } + *dash = '/'; + + havecontclass = 1; + for (unsigned short _i = 0; _i < entry->contclasslen; _i++) { + contclasses[(entry->contclass)[_i]] = 1; + } + } else { + entry->appnd = piece; + + if (ignorechars) { + if (utf8) { + remove_ignored_chars_utf(entry->appnd, ignorechars_utf16); + } else { + remove_ignored_chars(entry->appnd, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + reverseword_utf(entry->appnd); + else + reverseword(entry->appnd); + } + } + + if (entry->appnd.compare("0") == 0) { + entry->appnd.clear(); + } + break; + } + + // piece 5 - is the conditions descriptions + case 4: { + std::string chunk(piece); + np++; + if (complexprefixes) { + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + reverse_condition(chunk); + } + if (!entry->strip.empty() && chunk != "." && + redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(), + af->getlinenum())) + chunk = "."; + if (at == 'S') { + reverseword(chunk); + reverse_condition(chunk); + } + if (encodeit(*entry, chunk.c_str())) + return 1; + break; + } + + case 5: { + std::string chunk(piece); + np++; + if (pHMgr->is_aliasm()) { + int index = atoi(chunk.c_str()); + entry->morphcode = pHMgr->get_aliasm(index); + } else { + if (complexprefixes) { // XXX - fix me for morph. gen. + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + } + // add the remaining of the line + if (*tp) { + *(tp - 1) = ' '; + chunk.push_back(' '); + chunk.append(tp); + } + entry->morphcode = mystrdup(chunk.c_str()); + if (!entry->morphcode) + return 1; + } + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + // check to make sure we parsed enough pieces + if (np < 4) { + char* err = pHMgr->encode_flag(aflag); + if (err) { + HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err); + free(err); + } + return 1; + } + +#ifdef DEBUG + // detect unnecessary fields, excepting comments + if (basefieldnum) { + int fieldnum = + !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); + if (fieldnum != basefieldnum) + HUNSPELL_WARNING(stderr, "warning: line %d: bad field number\n", + af->getlinenum()); + } else { + basefieldnum = + !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6); + } +#endif + } + + // now create SfxEntry or PfxEntry objects and use links to + // build an ordered (sorted by affix string) list + for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) { + if (at == 'P') { + PfxEntry* pfxptr = new PfxEntry(this, &(*entry)); + build_pfxtree(pfxptr); + } else { + SfxEntry* sfxptr = new SfxEntry(this, &(*entry)); + build_sfxtree(sfxptr); + } + } + return 0; +} + +int AffixMgr::redundant_condition(char ft, + const char* strip, + int stripl, + const char* cond, + int linenum) { + int condl = strlen(cond); + int i; + int j; + int neg; + int in; + if (ft == 'P') { // prefix + if (strncmp(strip, cond, condl) == 0) + return 1; + if (utf8) { + } else { + for (i = 0, j = 0; (i < stripl) && (j < condl); i++, j++) { + if (cond[j] != '[') { + if (cond[j] != strip[i]) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } else { + neg = (cond[j + 1] == '^') ? 1 : 0; + in = 0; + do { + j++; + if (strip[i] == cond[j]) + in = 1; + } while ((j < (condl - 1)) && (cond[j] != ']')); + if (j == (condl - 1) && (cond[j] != ']')) { + HUNSPELL_WARNING(stderr, + "error: line %d: missing ] in condition:\n%s\n", + linenum, cond); + return 0; + } + if ((!neg && !in) || (neg && in)) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } + } + if (j >= condl) + return 1; + } + } else { // suffix + if ((stripl >= condl) && strcmp(strip + stripl - condl, cond) == 0) + return 1; + if (utf8) { + } else { + for (i = stripl - 1, j = condl - 1; (i >= 0) && (j >= 0); i--, j--) { + if (cond[j] != ']') { + if (cond[j] != strip[i]) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } else { + in = 0; + do { + j--; + if (strip[i] == cond[j]) + in = 1; + } while ((j > 0) && (cond[j] != '[')); + if ((j == 0) && (cond[j] != '[')) { + HUNSPELL_WARNING(stderr, + "error: line: %d: missing ] in condition:\n%s\n", + linenum, cond); + return 0; + } + neg = (cond[j + 1] == '^') ? 1 : 0; + if ((!neg && !in) || (neg && in)) { + HUNSPELL_WARNING(stderr, + "warning: line %d: incompatible stripping " + "characters and condition\n", + linenum); + return 0; + } + } + } + if (j < 0) + return 1; + } + } + return 0; +} + +int AffixMgr::get_suffix_words(short unsigned* suff, + int len, + const char* root_word, + char** slst) { + int suff_words_cnt = 0; + short unsigned* start_ptr = suff; + for (int j = 0; j < SETSIZE; j++) { + SfxEntry* ptr = sStart[j]; + while (ptr) { + suff = start_ptr; + for (int i = 0; i < len; i++) { + if ((*suff) == ptr->getFlag()) { + std::string nw(root_word); + nw.append(ptr->getAffix()); + hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, NULL, 0, + NULL, 0, 0, 0); + if (ht) { + slst[suff_words_cnt++] = mystrdup(nw.c_str()); + } + } + suff++; + } + ptr = ptr->getNext(); + } + } + return suff_words_cnt; +} diff --git a/extensions/spellcheck/hunspell/src/affixmgr.hxx b/extensions/spellcheck/hunspell/src/affixmgr.hxx new file mode 100644 index 000000000..d70e85338 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/affixmgr.hxx @@ -0,0 +1,390 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AFFIXMGR_HXX_ +#define _AFFIXMGR_HXX_ + +#include "hunvisapi.h" + +#include <stdio.h> + +#include <string> + +#include "atypes.hxx" +#include "baseaffix.hxx" +#include "hashmgr.hxx" +#include "phonet.hxx" +#include "replist.hxx" + +// check flag duplication +#define dupSFX (1 << 0) +#define dupPFX (1 << 1) + +class PfxEntry; +class SfxEntry; + +class LIBHUNSPELL_DLL_EXPORTED AffixMgr { + PfxEntry* pStart[SETSIZE]; + SfxEntry* sStart[SETSIZE]; + PfxEntry* pFlag[SETSIZE]; + SfxEntry* sFlag[SETSIZE]; + HashMgr* pHMgr; + HashMgr** alldic; + int* maxdic; + char* keystring; + char* trystring; + char* encoding; + struct cs_info* csconv; + int utf8; + int complexprefixes; + FLAG compoundflag; + FLAG compoundbegin; + FLAG compoundmiddle; + FLAG compoundend; + FLAG compoundroot; + FLAG compoundforbidflag; + FLAG compoundpermitflag; + int compoundmoresuffixes; + int checkcompounddup; + int checkcompoundrep; + int checkcompoundcase; + int checkcompoundtriple; + int simplifiedtriple; + FLAG forbiddenword; + FLAG nosuggest; + FLAG nongramsuggest; + FLAG needaffix; + int cpdmin; + int numrep; + replentry* reptable; + RepList* iconvtable; + RepList* oconvtable; + int nummap; + mapentry* maptable; + int numbreak; + char** breaktable; + int numcheckcpd; + patentry* checkcpdtable; + int simplifiedcpd; + int numdefcpd; + flagentry* defcpdtable; + phonetable* phone; + int maxngramsugs; + int maxcpdsugs; + int maxdiff; + int onlymaxdiff; + int nosplitsugs; + int sugswithdots; + int cpdwordmax; + int cpdmaxsyllable; + char* cpdvowels; + w_char* cpdvowels_utf16; + int cpdvowels_utf16_len; + char* cpdsyllablenum; + const char* pfxappnd; // BUG: not stateless + const char* sfxappnd; // BUG: not stateless + int sfxextra; // BUG: not stateless + FLAG sfxflag; // BUG: not stateless + char* derived; // BUG: not stateless + SfxEntry* sfx; // BUG: not stateless + PfxEntry* pfx; // BUG: not stateless + int checknum; + char* wordchars; + std::vector<w_char> wordchars_utf16; + char* ignorechars; + std::vector<w_char> ignorechars_utf16; + char* version; + char* lang; + int langnum; + FLAG lemma_present; + FLAG circumfix; + FLAG onlyincompound; + FLAG keepcase; + FLAG forceucase; + FLAG warn; + int forbidwarn; + FLAG substandard; + int checksharps; + int fullstrip; + + int havecontclass; // boolean variable + char contclasses[CONTSIZE]; // flags of possible continuing classes (twofold + // affix) + + public: + AffixMgr(const char* affpath, HashMgr** ptr, int* md, const char* key = NULL); + ~AffixMgr(); + struct hentry* affix_check(const char* word, + int len, + const unsigned short needflag = (unsigned short)0, + char in_compound = IN_CPD_NOT); + struct hentry* prefix_check(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + inline int isSubset(const char* s1, const char* s2); + struct hentry* prefix_check_twosfx(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + inline int isRevSubset(const char* s1, const char* end_of_s2, int len); + struct hentry* suffix_check(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + char** wlst, + int maxSug, + int* ns, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + struct hentry* suffix_check_twosfx(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* affix_check_morph(const char* word, + int len, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + char* prefix_check_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + char* suffix_check_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass = FLAG_NULL, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + + char* prefix_check_twosfx_morph(const char* word, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + char* suffix_check_twosfx_morph(const char* word, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + char* morphgen(const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* morph, + const char* targetmorph, + int level); + + int expand_rootword(struct guessword* wlst, + int maxn, + const char* ts, + int wl, + const unsigned short* ap, + unsigned short al, + const char* bad, + int, + const char*); + + short get_syllable(const std::string& word); + int cpdrep_check(const char* word, int len); + int cpdpat_check(const char* word, + int len, + hentry* r1, + hentry* r2, + const char affixed); + int defcpd_check(hentry*** words, + short wnum, + hentry* rv, + hentry** rwords, + char all); + int cpdcase_check(const char* word, int len); + inline int candidate_check(const char* word, int len); + void setcminmax(int* cmin, int* cmax, const char* word, int len); + struct hentry* compound_check(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule, + char is_sug, + int* info); + + int compound_check_morph(const char* word, + int len, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule, + char** result, + char* partresult); + + int get_suffix_words(short unsigned* suff, + int len, + const char* root_word, + char** slst); + + struct hentry* lookup(const char* word); + int get_numrep() const; + struct replentry* get_reptable() const; + RepList* get_iconvtable() const; + RepList* get_oconvtable() const; + struct phonetable* get_phonetable() const; + int get_nummap() const; + struct mapentry* get_maptable() const; + int get_numbreak() const; + char** get_breaktable() const; + char* get_encoding(); + int get_langnum() const; + char* get_key_string(); + char* get_try_string() const; + const char* get_wordchars() const; + const std::vector<w_char>& get_wordchars_utf16() const; + char* get_ignore() const; + const std::vector<w_char>& get_ignore_utf16() const; + int get_compound() const; + FLAG get_compoundflag() const; + FLAG get_compoundbegin() const; + FLAG get_forbiddenword() const; + FLAG get_nosuggest() const; + FLAG get_nongramsuggest() const; + FLAG get_needaffix() const; + FLAG get_onlyincompound() const; + FLAG get_compoundroot() const; + FLAG get_lemma_present() const; + int get_checknum() const; + const char* get_prefix() const; + const char* get_suffix() const; + const char* get_derived() const; + const char* get_version() const; + int have_contclass() const; + int get_utf8() const; + int get_complexprefixes() const; + char* get_suffixed(char) const; + int get_maxngramsugs() const; + int get_maxcpdsugs() const; + int get_maxdiff() const; + int get_onlymaxdiff() const; + int get_nosplitsugs() const; + int get_sugswithdots(void) const; + FLAG get_keepcase(void) const; + FLAG get_forceucase(void) const; + FLAG get_warn(void) const; + int get_forbidwarn(void) const; + int get_checksharps(void) const; + char* encode_flag(unsigned short aflag) const; + int get_fullstrip() const; + + private: + int parse_file(const char* affpath, const char* key); + int parse_flag(char* line, unsigned short* out, FileMgr* af); + int parse_num(char* line, int* out, FileMgr* af); + int parse_cpdsyllable(char* line, FileMgr* af); + int parse_reptable(char* line, FileMgr* af); + int parse_convtable(char* line, + FileMgr* af, + RepList** rl, + const char* keyword); + int parse_phonetable(char* line, FileMgr* af); + int parse_maptable(char* line, FileMgr* af); + int parse_breaktable(char* line, FileMgr* af); + int parse_checkcpdtable(char* line, FileMgr* af); + int parse_defcpdtable(char* line, FileMgr* af); + int parse_affix(char* line, const char at, FileMgr* af, char* dupflags); + + void reverse_condition(std::string&); + void debugflag(char* result, unsigned short flag); + std::string& debugflag(std::string& result, unsigned short flag); + int condlen(const char*); + int encodeit(affentry& entry, const char* cs); + int build_pfxtree(PfxEntry* pfxptr); + int build_sfxtree(SfxEntry* sfxptr); + int process_pfx_order(); + int process_sfx_order(); + PfxEntry* process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr); + SfxEntry* process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr); + int process_pfx_tree_to_list(); + int process_sfx_tree_to_list(); + int redundant_condition(char, const char* strip, int stripl, const char* cond, int); + void finishFileMgr(FileMgr* afflst); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/atypes.hxx b/extensions/spellcheck/hunspell/src/atypes.hxx new file mode 100644 index 000000000..60826af20 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/atypes.hxx @@ -0,0 +1,145 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _ATYPES_HXX_ +#define _ATYPES_HXX_ + +#ifndef HUNSPELL_WARNING +#include <stdio.h> +#ifdef HUNSPELL_WARNING_ON +#define HUNSPELL_WARNING fprintf +#else +// empty inline function to switch off warnings (instead of the C99 standard +// variadic macros) +static inline void HUNSPELL_WARNING(FILE*, const char*, ...) {} +#endif +#endif + +// HUNSTEM def. +#define HUNSTEM + +#include "hashmgr.hxx" +#include "w_char.hxx" +#include <algorithm> +#include <string> + +#define SETSIZE 256 +#define CONTSIZE 65536 + +// affentry options +#define aeXPRODUCT (1 << 0) +#define aeUTF8 (1 << 1) +#define aeALIASF (1 << 2) +#define aeALIASM (1 << 3) +#define aeLONGCOND (1 << 4) + +// compound options +#define IN_CPD_NOT 0 +#define IN_CPD_BEGIN 1 +#define IN_CPD_END 2 +#define IN_CPD_OTHER 3 + +// info options +#define SPELL_COMPOUND (1 << 0) +#define SPELL_FORBIDDEN (1 << 1) +#define SPELL_ALLCAP (1 << 2) +#define SPELL_NOCAP (1 << 3) +#define SPELL_INITCAP (1 << 4) +#define SPELL_ORIGCAP (1 << 5) +#define SPELL_WARN (1 << 6) + +#define MAXLNLEN 8192 + +#define MINCPDLEN 3 +#define MAXCOMPOUND 10 +#define MAXCONDLEN 20 +#define MAXCONDLEN_1 (MAXCONDLEN - sizeof(char*)) + +#define MAXACC 1000 + +#define FLAG unsigned short +#define FLAG_NULL 0x00 +#define FREE_FLAG(a) a = 0 + +#define TESTAFF(a, b, c) (std::binary_search(a, a + c, b)) + +struct affentry { + std::string strip; + std::string appnd; + char numconds; + char opts; + unsigned short aflag; + unsigned short* contclass; + short contclasslen; + union { + char conds[MAXCONDLEN]; + struct { + char conds1[MAXCONDLEN_1]; + char* conds2; + } l; + } c; + char* morphcode; +}; + +struct guessword { + char* word; + bool allow; + char* orig; +}; + +struct mapentry { + char** set; + int len; +}; + +struct flagentry { + FLAG* def; + int len; +}; + +struct patentry { + char* pattern; + char* pattern2; + char* pattern3; + FLAG cond; + FLAG cond2; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/baseaffix.hxx b/extensions/spellcheck/hunspell/src/baseaffix.hxx new file mode 100644 index 000000000..59256e92f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/baseaffix.hxx @@ -0,0 +1,77 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _BASEAFF_HXX_ +#define _BASEAFF_HXX_ + +#include "hunvisapi.h" +#include <string> + +class LIBHUNSPELL_DLL_EXPORTED AffEntry { + private: + AffEntry(const AffEntry&); + AffEntry& operator=(const AffEntry&); + + protected: + AffEntry() + : numconds(0), + opts(0), + aflag(0), + morphcode(0), + contclass(NULL), + contclasslen(0) {} + std::string appnd; + std::string strip; + unsigned char numconds; + char opts; + unsigned short aflag; + union { + char conds[MAXCONDLEN]; + struct { + char conds1[MAXCONDLEN_1]; + char* conds2; + } l; + } c; + char* morphcode; + unsigned short* contclass; + short contclasslen; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/csutil.cxx b/extensions/spellcheck/hunspell/src/csutil.cxx new file mode 100644 index 000000000..1948e4a3b --- /dev/null +++ b/extensions/spellcheck/hunspell/src/csutil.cxx @@ -0,0 +1,2850 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <algorithm> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "csutil.hxx" +#include "atypes.hxx" +#include "langnum.hxx" + +// Unicode character encoding information +struct unicode_info { + unsigned short c; + unsigned short cupper; + unsigned short clower; +}; + +#ifdef _WIN32 +#include <windows.h> +#include <wchar.h> +#endif + +#ifdef OPENOFFICEORG +#include <unicode/uchar.h> +#else +#ifndef MOZILLA_CLIENT +#include "utf_info.cxx" +#define UTF_LST_LEN (sizeof(utf_lst) / (sizeof(unicode_info))) +#endif +#endif + +#ifdef MOZILLA_CLIENT +#include "nsCOMPtr.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "nsUnicharUtils.h" +#include "mozilla/dom/EncodingUtils.h" + +using mozilla::dom::EncodingUtils; +#endif + +struct unicode_info2 { + char cletter; + unsigned short cupper; + unsigned short clower; +}; + +static struct unicode_info2* utf_tbl = NULL; +static int utf_tbl_count = + 0; // utf_tbl can be used by multiple Hunspell instances + +FILE* myfopen(const char* path, const char* mode) { +#ifdef _WIN32 +#define WIN32_LONG_PATH_PREFIX "\\\\?\\" + if (strncmp(path, WIN32_LONG_PATH_PREFIX, 4) == 0) { + int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + wchar_t* buff = (wchar_t*)malloc(len * sizeof(wchar_t)); + wchar_t* buff2 = (wchar_t*)malloc(len * sizeof(wchar_t)); + FILE* f = NULL; + if (buff && buff2) { + MultiByteToWideChar(CP_UTF8, 0, path, -1, buff, len); + if (_wfullpath(buff2, buff, len) != NULL) { + f = _wfopen(buff2, (strcmp(mode, "r") == 0) ? L"r" : L"rb"); + } + free(buff); + free(buff2); + } + return f; + } +#endif + return fopen(path, mode); +} + +std::string& u16_u8(std::string& dest, const std::vector<w_char>& src) { + dest.clear(); + std::vector<w_char>::const_iterator u2 = src.begin(); + std::vector<w_char>::const_iterator u2_max = src.end(); + while (u2 < u2_max) { + signed char u8; + if (u2->h) { // > 0xFF + // XXX 4-byte haven't implemented yet. + if (u2->h >= 0x08) { // >= 0x800 (3-byte UTF-8 character) + u8 = 0xe0 + (u2->h >> 4); + dest.push_back(u8); + u8 = 0x80 + ((u2->h & 0xf) << 2) + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } else { // < 0x800 (2-byte UTF-8 character) + u8 = 0xc0 + (u2->h << 2) + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } + } else { // <= 0xFF + if (u2->l & 0x80) { // >0x80 (2-byte UTF-8 character) + u8 = 0xc0 + (u2->l >> 6); + dest.push_back(u8); + u8 = 0x80 + (u2->l & 0x3f); + dest.push_back(u8); + } else { // < 0x80 (1-byte UTF-8 character) + u8 = u2->l; + dest.push_back(u8); + } + } + ++u2; + } + return dest; +} + +int u8_u16(std::vector<w_char>& dest, const std::string& src) { + dest.clear(); + std::string::const_iterator u8 = src.begin(); + std::string::const_iterator u8_max = src.end(); + + while (u8 < u8_max) { + w_char u2; + switch ((*u8) & 0xf0) { + case 0x00: + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: { + u2.h = 0; + u2.l = *u8; + break; + } + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Unexpected continuation bytes " + "in %ld. character position\n%s\n", + static_cast<long>(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + break; + } + case 0xc0: + case 0xd0: { // 2-byte UTF-8 codes + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.h = (*u8 & 0x1f) >> 2; + u2.l = (*u8 << 6) + (*(u8 + 1) & 0x3f); + ++u8; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte in " + "%ld. character position:\n%s\n", + static_cast<long>(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + break; + } + case 0xe0: { // 3-byte UTF-8 codes + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.h = ((*u8 & 0x0f) << 4) + ((*(u8 + 1) & 0x3f) >> 2); + ++u8; + if ((*(u8 + 1) & 0xc0) == 0x80) { + u2.l = (static_cast<unsigned char>(*u8) << 6) + (*(u8 + 1) & 0x3f); + ++u8; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte " + "in %ld. character position:\n%s\n", + static_cast<long>(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing continuation byte in " + "%ld. character position:\n%s\n", + static_cast<long>(std::distance(src.begin(), u8)), + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + } + break; + } + case 0xf0: { // 4 or more byte UTF-8 codes + HUNSPELL_WARNING(stderr, + "This UTF-8 encoding can't convert to UTF-16:\n%s\n", + src.c_str()); + u2.h = 0xff; + u2.l = 0xfd; + dest.push_back(u2); + return -1; + } + } + dest.push_back(u2); + ++u8; + } + + return dest.size(); +} + +// strip strings into token based on single char delimiter +// acts like strsep() but only uses a delim char and not +// a delim string +// default delimiter: white space characters + +char* mystrsep(char** stringp, const char delim) { + char* mp = *stringp; + if (*mp != '\0') { + char* dp; + if (delim) { + dp = strchr(mp, delim); + } else { + // don't use isspace() here, the string can be in some random charset + // that's way different than the locale's + for (dp = mp; (*dp && *dp != ' ' && *dp != '\t'); dp++) + ; + if (!*dp) + dp = NULL; + } + if (dp) { + *stringp = dp + 1; + *dp = '\0'; + } else { + *stringp = mp + strlen(mp); + } + return mp; + } + return NULL; +} + +// replaces strdup with ansi version +char* mystrdup(const char* s) { + char* d = NULL; + if (s) { + size_t sl = strlen(s) + 1; + d = (char*)malloc(sl); + if (d) { + memcpy(d, s, sl); + } else { + HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); + } + } + return d; +} + +// strcat for limited length destination string +char* mystrcat(char* dest, const char* st, int max) { + int len; + int len2; + if (dest == NULL || st == NULL) + return dest; + len = strlen(dest); + len2 = strlen(st); + if (len + len2 + 1 > max) + return dest; + strcpy(dest + len, st); + return dest; +} + +// remove cross-platform text line end characters +void mychomp(char* s) { + size_t k = strlen(s); + if ((k > 0) && ((*(s + k - 1) == '\r') || (*(s + k - 1) == '\n'))) + *(s + k - 1) = '\0'; + if ((k > 1) && (*(s + k - 2) == '\r')) + *(s + k - 2) = '\0'; +} + +// break text to lines +// return number of lines +int line_tok(const char* text, char*** lines, char breakchar) { + int linenum = 0; + if (!text) { + return linenum; + } + char* dup = mystrdup(text); + char* p = strchr(dup, breakchar); + while (p) { + linenum++; + *p = '\0'; + p++; + p = strchr(p, breakchar); + } + linenum++; + *lines = (char**)malloc(linenum * sizeof(char*)); + if (!(*lines)) { + free(dup); + return 0; + } + + p = dup; + int l = 0; + for (int i = 0; i < linenum; i++) { + if (*p != '\0') { + (*lines)[l] = mystrdup(p); + if (!(*lines)[l]) { + for (i = 0; i < l; i++) + free((*lines)[i]); + free(dup); + return 0; + } + l++; + } + p += strlen(p) + 1; + } + free(dup); + if (!l) { + free(*lines); + *lines = NULL; + } + return l; +} + +// uniq line in place +char* line_uniq(char* text, char breakchar) { + char** lines; + int linenum = line_tok(text, &lines, breakchar); + int i; + strcpy(text, lines[0]); + for (i = 1; i < linenum; i++) { + int dup = 0; + for (int j = 0; j < i; j++) { + if (strcmp(lines[i], lines[j]) == 0) { + dup = 1; + break; + } + } + if (!dup) { + if ((i > 1) || (*(lines[0]) != '\0')) { + sprintf(text + strlen(text), "%c", breakchar); + } + strcat(text, lines[i]); + } + } + for (i = 0; i < linenum; i++) { + free(lines[i]); + } + free(lines); + return text; +} + +// uniq and boundary for compound analysis: "1\n\2\n\1" -> " ( \1 | \2 ) " +char* line_uniq_app(char** text, char breakchar) { + if (!strchr(*text, breakchar)) { + return *text; + } + + char** lines; + int i; + int linenum = line_tok(*text, &lines, breakchar); + int dup = 0; + for (i = 0; i < linenum; i++) { + for (int j = 0; j < (i - 1); j++) { + if (strcmp(lines[i], lines[j]) == 0) { + *(lines[i]) = '\0'; + dup++; + break; + } + } + } + if ((linenum - dup) == 1) { + strcpy(*text, lines[0]); + freelist(&lines, linenum); + return *text; + } + char* newtext = (char*)malloc(strlen(*text) + 2 * linenum + 3 + 1); + if (newtext) { + free(*text); + *text = newtext; + } else { + freelist(&lines, linenum); + return *text; + } + strcpy(*text, " ( "); + for (i = 0; i < linenum; i++) + if (*(lines[i])) { + sprintf(*text + strlen(*text), "%s%s", lines[i], " | "); + } + (*text)[strlen(*text) - 2] = ')'; // " ) " + freelist(&lines, linenum); + return *text; +} + +// append s to ends of every lines in text +std::string& strlinecat(std::string& str, const std::string& apd) { + size_t pos = 0; + while ((pos = str.find('\n', pos)) != std::string::npos) { + str.insert(pos, apd); + pos += apd.length() + 1; + } + str.append(apd); + return str; +} + +// morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields +// in the first line of the inputs +// return 0, if inputs equal +// return 1, if inputs may equal with a secondary suffix +// otherwise return -1 +int morphcmp(const char* s, const char* t) { + int se = 0; + int te = 0; + const char* sl; + const char* tl; + const char* olds; + const char* oldt; + if (!s || !t) + return 1; + olds = s; + sl = strchr(s, '\n'); + s = strstr(s, MORPH_DERI_SFX); + if (!s || (sl && sl < s)) + s = strstr(olds, MORPH_INFL_SFX); + if (!s || (sl && sl < s)) { + s = strstr(olds, MORPH_TERM_SFX); + olds = NULL; + } + oldt = t; + tl = strchr(t, '\n'); + t = strstr(t, MORPH_DERI_SFX); + if (!t || (tl && tl < t)) + t = strstr(oldt, MORPH_INFL_SFX); + if (!t || (tl && tl < t)) { + t = strstr(oldt, MORPH_TERM_SFX); + oldt = NULL; + } + while (s && t && (!sl || sl > s) && (!tl || tl > t)) { + s += MORPH_TAG_LEN; + t += MORPH_TAG_LEN; + se = 0; + te = 0; + while ((*s == *t) && !se && !te) { + s++; + t++; + switch (*s) { + case ' ': + case '\n': + case '\t': + case '\0': + se = 1; + } + switch (*t) { + case ' ': + case '\n': + case '\t': + case '\0': + te = 1; + } + } + if (!se || !te) { + // not terminal suffix difference + if (olds) + return -1; + return 1; + } + olds = s; + s = strstr(s, MORPH_DERI_SFX); + if (!s || (sl && sl < s)) + s = strstr(olds, MORPH_INFL_SFX); + if (!s || (sl && sl < s)) { + s = strstr(olds, MORPH_TERM_SFX); + olds = NULL; + } + oldt = t; + t = strstr(t, MORPH_DERI_SFX); + if (!t || (tl && tl < t)) + t = strstr(oldt, MORPH_INFL_SFX); + if (!t || (tl && tl < t)) { + t = strstr(oldt, MORPH_TERM_SFX); + oldt = NULL; + } + } + if (!s && !t && se && te) + return 0; + return 1; +} + +int get_sfxcount(const char* morph) { + if (!morph || !*morph) + return 0; + int n = 0; + const char* old = morph; + morph = strstr(morph, MORPH_DERI_SFX); + if (!morph) + morph = strstr(old, MORPH_INFL_SFX); + if (!morph) + morph = strstr(old, MORPH_TERM_SFX); + while (morph) { + n++; + old = morph; + morph = strstr(morph + 1, MORPH_DERI_SFX); + if (!morph) + morph = strstr(old + 1, MORPH_INFL_SFX); + if (!morph) + morph = strstr(old + 1, MORPH_TERM_SFX); + } + return n; +} + +int fieldlen(const char* r) { + int n = 0; + while (r && *r != ' ' && *r != '\t' && *r != '\0' && *r != '\n') { + r++; + n++; + } + return n; +} + +bool copy_field(std::string& dest, + const std::string& morph, + const std::string& var) { + if (morph.empty()) + return false; + size_t pos = morph.find(var); + if (pos == std::string::npos) + return false; + dest.clear(); + std::string beg(morph.substr(pos + MORPH_TAG_LEN, std::string::npos)); + + for (size_t i = 0; i < beg.size(); ++i) { + const char c(beg[i]); + if (c == ' ' || c == '\t' || c == '\n') + break; + dest.push_back(c); + } + + return true; +} + +std::string& mystrrep(std::string& str, + const std::string& search, + const std::string& replace) { + size_t pos = 0; + while ((pos = str.find(search, pos)) != std::string::npos) { + str.replace(pos, search.length(), replace); + pos += replace.length(); + } + return str; +} + +char* mystrrep(char* word, const char* pat, const char* rep) { + char* pos = strstr(word, pat); + if (pos) { + int replen = strlen(rep); + int patlen = strlen(pat); + while (pos) { + if (replen < patlen) { + char* end = word + strlen(word); + char* next = pos + replen; + char* prev = pos + strlen(pat); + for (; prev < end;* next = *prev, prev++, next++) + ; + *next = '\0'; + } else if (replen > patlen) { + char* end = pos + patlen; + char* next = word + strlen(word) + replen - patlen; + char* prev = next - replen + patlen; + for (; prev >= end;* next = *prev, prev--, next--) + ; + } + strncpy(pos, rep, replen); + pos = strstr(word, pat); + } + } + return word; +} + +// reverse word +size_t reverseword(std::string& word) { + std::reverse(word.begin(), word.end()); + return word.size(); +} + +// reverse word +size_t reverseword_utf(std::string& word) { + std::vector<w_char> w; + u8_u16(w, word); + std::reverse(w.begin(), w.end()); + u16_u8(word, w); + return w.size(); +} + +int uniqlist(char** list, int n) { + int i; + if (n < 2) + return n; + for (i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (list[j] && list[i] && (strcmp(list[j], list[i]) == 0)) { + free(list[i]); + list[i] = NULL; + break; + } + } + } + int m = 1; + for (i = 1; i < n; i++) + if (list[i]) { + list[m] = list[i]; + m++; + } + return m; +} + +void freelist(char*** list, int n) { + if (list && *list) { + for (int i = 0; i < n; i++) + free((*list)[i]); + free(*list); + *list = NULL; + } +} + +namespace { +unsigned char cupper(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].cupper; +} + +unsigned char clower(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].clower; +} + +unsigned char ccase(const struct cs_info* csconv, int nIndex) { + if (nIndex < 0 || nIndex > 255) + return nIndex; + return csconv[nIndex].ccase; +} +} + +w_char upper_utf(w_char u, int langnum) { + unsigned short idx = (u.h << 8) + u.l; + if (idx != unicodetoupper(idx, langnum)) { + u.h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u.l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + return u; +} + +w_char lower_utf(w_char u, int langnum) { + unsigned short idx = (u.h << 8) + u.l; + if (idx != unicodetolower(idx, langnum)) { + u.h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u.l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + return u; +} + +// convert std::string to all caps +std::string& mkallcap(std::string& s, const struct cs_info* csconv) { + for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { + *aI = cupper(csconv, static_cast<unsigned char>(*aI)); + } + return s; +} + +// convert std::string to all little +std::string& mkallsmall(std::string& s, const struct cs_info* csconv) { + for (std::string::iterator aI = s.begin(), aEnd = s.end(); aI != aEnd; ++aI) { + *aI = clower(csconv, static_cast<unsigned char>(*aI)); + } + return s; +} + +std::vector<w_char>& mkallsmall_utf(std::vector<w_char>& u, + int langnum) { + for (size_t i = 0; i < u.size(); ++i) { + unsigned short idx = (u[i].h << 8) + u[i].l; + if (idx != unicodetolower(idx, langnum)) { + u[i].h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u[i].l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::vector<w_char>& mkallcap_utf(std::vector<w_char>& u, int langnum) { + for (size_t i = 0; i < u.size(); i++) { + unsigned short idx = (u[i].h << 8) + u[i].l; + if (idx != unicodetoupper(idx, langnum)) { + u[i].h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u[i].l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::string& mkinitcap(std::string& s, const struct cs_info* csconv) { + if (!s.empty()) { + s[0] = cupper(csconv, static_cast<unsigned char>(s[0])); + } + return s; +} + +std::vector<w_char>& mkinitcap_utf(std::vector<w_char>& u, int langnum) { + if (!u.empty()) { + unsigned short idx = (u[0].h << 8) + u[0].l; + if (idx != unicodetoupper(idx, langnum)) { + u[0].h = (unsigned char)(unicodetoupper(idx, langnum) >> 8); + u[0].l = (unsigned char)(unicodetoupper(idx, langnum) & 0x00FF); + } + } + return u; +} + +std::string& mkinitsmall(std::string& s, const struct cs_info* csconv) { + if (!s.empty()) { + s[0] = clower(csconv, static_cast<unsigned char>(s[0])); + } + return s; +} + +std::vector<w_char>& mkinitsmall_utf(std::vector<w_char>& u, int langnum) { + if (!u.empty()) { + unsigned short idx = (u[0].h << 8) + u[0].l; + if (idx != unicodetolower(idx, langnum)) { + u[0].h = (unsigned char)(unicodetolower(idx, langnum) >> 8); + u[0].l = (unsigned char)(unicodetolower(idx, langnum) & 0x00FF); + } + } + return u; +} + +// conversion function for protected memory +void store_pointer(char* dest, char* source) { + memcpy(dest, &source, sizeof(char*)); +} + +// conversion function for protected memory +char* get_stored_pointer(const char* s) { + char* p; + memcpy(&p, s, sizeof(char*)); + return p; +} + +#ifndef MOZILLA_CLIENT + +// these are simple character mappings for the +// encodings supported +// supplying isupper, tolower, and toupper + +static struct cs_info iso1_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso2_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xbe, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso3_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0x69, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0x49}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso4_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xb1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x01, 0xb3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb5, 0xa5}, {0x01, 0xb6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x01, 0xb9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x01, 0xbb, 0xab}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xbe, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xa1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xa3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xa5}, {0x00, 0xb6, 0xa6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xa9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xab}, {0x00, 0xbc, 0xac}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xae}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso5_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xf1, 0xa1}, + {0x01, 0xf2, 0xa2}, {0x01, 0xf3, 0xa3}, {0x01, 0xf4, 0xa4}, + {0x01, 0xf5, 0xa5}, {0x01, 0xf6, 0xa6}, {0x01, 0xf7, 0xa7}, + {0x01, 0xf8, 0xa8}, {0x01, 0xf9, 0xa9}, {0x01, 0xfa, 0xaa}, + {0x01, 0xfb, 0xab}, {0x01, 0xfc, 0xac}, {0x00, 0xad, 0xad}, + {0x01, 0xfe, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xd0, 0xb0}, + {0x01, 0xd1, 0xb1}, {0x01, 0xd2, 0xb2}, {0x01, 0xd3, 0xb3}, + {0x01, 0xd4, 0xb4}, {0x01, 0xd5, 0xb5}, {0x01, 0xd6, 0xb6}, + {0x01, 0xd7, 0xb7}, {0x01, 0xd8, 0xb8}, {0x01, 0xd9, 0xb9}, + {0x01, 0xda, 0xba}, {0x01, 0xdb, 0xbb}, {0x01, 0xdc, 0xbc}, + {0x01, 0xdd, 0xbd}, {0x01, 0xde, 0xbe}, {0x01, 0xdf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x00, 0xd0, 0xb0}, {0x00, 0xd1, 0xb1}, + {0x00, 0xd2, 0xb2}, {0x00, 0xd3, 0xb3}, {0x00, 0xd4, 0xb4}, + {0x00, 0xd5, 0xb5}, {0x00, 0xd6, 0xb6}, {0x00, 0xd7, 0xb7}, + {0x00, 0xd8, 0xb8}, {0x00, 0xd9, 0xb9}, {0x00, 0xda, 0xba}, + {0x00, 0xdb, 0xbb}, {0x00, 0xdc, 0xbc}, {0x00, 0xdd, 0xbd}, + {0x00, 0xde, 0xbe}, {0x00, 0xdf, 0xbf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xa1}, {0x00, 0xf2, 0xa2}, + {0x00, 0xf3, 0xa3}, {0x00, 0xf4, 0xa4}, {0x00, 0xf5, 0xa5}, + {0x00, 0xf6, 0xa6}, {0x00, 0xf7, 0xa7}, {0x00, 0xf8, 0xa8}, + {0x00, 0xf9, 0xa9}, {0x00, 0xfa, 0xaa}, {0x00, 0xfb, 0xab}, + {0x00, 0xfc, 0xac}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xae}, + {0x00, 0xff, 0xaf}}; + +static struct cs_info iso6_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso7_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x01, 0xdc, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x01, 0xdd, 0xb8}, {0x01, 0xde, 0xb9}, + {0x01, 0xdf, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xfc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x01, 0xfd, 0xbe}, {0x01, 0xfe, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x00, 0xdc, 0xb6}, {0x00, 0xdd, 0xb8}, + {0x00, 0xde, 0xb9}, {0x00, 0xdf, 0xba}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd3}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xbc}, {0x00, 0xfd, 0xbe}, {0x00, 0xfe, 0xbf}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso8_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso9_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0xfd, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0xdd}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0x69, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0x49}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso10_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info koi8r_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xe0}, {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, + {0x00, 0xc3, 0xe3}, {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, + {0x00, 0xc6, 0xe6}, {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, + {0x00, 0xc9, 0xe9}, {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, + {0x00, 0xcc, 0xec}, {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, + {0x00, 0xcf, 0xef}, {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, + {0x00, 0xd2, 0xf2}, {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, + {0x00, 0xd5, 0xf5}, {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, + {0x00, 0xd8, 0xf8}, {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, + {0x00, 0xdb, 0xfb}, {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, + {0x00, 0xde, 0xfe}, {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, + {0x01, 0xc1, 0xe1}, {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, + {0x01, 0xc4, 0xe4}, {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, + {0x01, 0xc7, 0xe7}, {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, + {0x01, 0xca, 0xea}, {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, + {0x01, 0xcd, 0xed}, {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, + {0x01, 0xd0, 0xf0}, {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, + {0x01, 0xd3, 0xf3}, {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, + {0x01, 0xd6, 0xf6}, {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, + {0x01, 0xd9, 0xf9}, {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, + {0x01, 0xdc, 0xfc}, {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, + {0x01, 0xdf, 0xff}}; + +static struct cs_info koi8u_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xb3}, {0x00, 0xa4, 0xb4}, /* ie */ + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xb6}, /* i */ + {0x00, 0xa7, 0xb7}, /* ii */ + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xbd}, /* g'' */ + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x01, 0xa3, 0xb3}, + {0x00, 0xb4, 0xb4}, /* IE */ + {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, /* I */ + {0x00, 0xb7, 0xb7}, /* II */ + {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, {0x00, 0xba, 0xba}, + {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, {0x00, 0xbd, 0xbd}, + {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, {0x00, 0xc0, 0xe0}, + {0x00, 0xc1, 0xe1}, {0x00, 0xc2, 0xe2}, {0x00, 0xc3, 0xe3}, + {0x00, 0xc4, 0xe4}, {0x00, 0xc5, 0xe5}, {0x00, 0xc6, 0xe6}, + {0x00, 0xc7, 0xe7}, {0x00, 0xc8, 0xe8}, {0x00, 0xc9, 0xe9}, + {0x00, 0xca, 0xea}, {0x00, 0xcb, 0xeb}, {0x00, 0xcc, 0xec}, + {0x00, 0xcd, 0xed}, {0x00, 0xce, 0xee}, {0x00, 0xcf, 0xef}, + {0x00, 0xd0, 0xf0}, {0x00, 0xd1, 0xf1}, {0x00, 0xd2, 0xf2}, + {0x00, 0xd3, 0xf3}, {0x00, 0xd4, 0xf4}, {0x00, 0xd5, 0xf5}, + {0x00, 0xd6, 0xf6}, {0x00, 0xd7, 0xf7}, {0x00, 0xd8, 0xf8}, + {0x00, 0xd9, 0xf9}, {0x00, 0xda, 0xfa}, {0x00, 0xdb, 0xfb}, + {0x00, 0xdc, 0xfc}, {0x00, 0xdd, 0xfd}, {0x00, 0xde, 0xfe}, + {0x00, 0xdf, 0xff}, {0x01, 0xc0, 0xe0}, {0x01, 0xc1, 0xe1}, + {0x01, 0xc2, 0xe2}, {0x01, 0xc3, 0xe3}, {0x01, 0xc4, 0xe4}, + {0x01, 0xc5, 0xe5}, {0x01, 0xc6, 0xe6}, {0x01, 0xc7, 0xe7}, + {0x01, 0xc8, 0xe8}, {0x01, 0xc9, 0xe9}, {0x01, 0xca, 0xea}, + {0x01, 0xcb, 0xeb}, {0x01, 0xcc, 0xec}, {0x01, 0xcd, 0xed}, + {0x01, 0xce, 0xee}, {0x01, 0xcf, 0xef}, {0x01, 0xd0, 0xf0}, + {0x01, 0xd1, 0xf1}, {0x01, 0xd2, 0xf2}, {0x01, 0xd3, 0xf3}, + {0x01, 0xd4, 0xf4}, {0x01, 0xd5, 0xf5}, {0x01, 0xd6, 0xf6}, + {0x01, 0xd7, 0xf7}, {0x01, 0xd8, 0xf8}, {0x01, 0xd9, 0xf9}, + {0x01, 0xda, 0xfa}, {0x01, 0xdb, 0xfb}, {0x01, 0xdc, 0xfc}, + {0x01, 0xdd, 0xfd}, {0x01, 0xde, 0xfe}, {0x01, 0xdf, 0xff}}; + +static struct cs_info cp1251_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x01, 0x90, 0x80}, + {0x01, 0x83, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x81}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x01, 0x9a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x01, 0x9c, 0x8c}, + {0x01, 0x9d, 0x8d}, {0x01, 0x9e, 0x8e}, {0x01, 0x9f, 0x8f}, + {0x00, 0x90, 0x80}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x8a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x8c}, {0x00, 0x9d, 0x8d}, {0x00, 0x9e, 0x8e}, + {0x00, 0x9f, 0x8f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, + {0x00, 0xa2, 0xa1}, {0x01, 0xbc, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x01, 0xb4, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xbf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, + {0x00, 0xb4, 0xa5}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xaa}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xa3}, + {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xaf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x01, 0xff, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xdf}}; + +static struct cs_info iso13_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0A, 0x0A}, {0x00, 0x0B, 0x0B}, + {0x00, 0x0C, 0x0C}, {0x00, 0x0D, 0x0D}, {0x00, 0x0E, 0x0E}, + {0x00, 0x0F, 0x0F}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1A, 0x1A}, + {0x00, 0x1B, 0x1B}, {0x00, 0x1C, 0x1C}, {0x00, 0x1D, 0x1D}, + {0x00, 0x1E, 0x1E}, {0x00, 0x1F, 0x1F}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2A, 0x2A}, {0x00, 0x2B, 0x2B}, {0x00, 0x2C, 0x2C}, + {0x00, 0x2D, 0x2D}, {0x00, 0x2E, 0x2E}, {0x00, 0x2F, 0x2F}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3A, 0x3A}, {0x00, 0x3B, 0x3B}, + {0x00, 0x3C, 0x3C}, {0x00, 0x3D, 0x3D}, {0x00, 0x3E, 0x3E}, + {0x00, 0x3F, 0x3F}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6A, 0x4A}, + {0x01, 0x6B, 0x4B}, {0x01, 0x6C, 0x4C}, {0x01, 0x6D, 0x4D}, + {0x01, 0x6E, 0x4E}, {0x01, 0x6F, 0x4F}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7A, 0x5A}, {0x00, 0x5B, 0x5B}, {0x00, 0x5C, 0x5C}, + {0x00, 0x5D, 0x5D}, {0x00, 0x5E, 0x5E}, {0x00, 0x5F, 0x5F}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6A, 0x4A}, {0x00, 0x6B, 0x4B}, + {0x00, 0x6C, 0x4C}, {0x00, 0x6D, 0x4D}, {0x00, 0x6E, 0x4E}, + {0x00, 0x6F, 0x4F}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7A, 0x5A}, + {0x00, 0x7B, 0x7B}, {0x00, 0x7C, 0x7C}, {0x00, 0x7D, 0x7D}, + {0x00, 0x7E, 0x7E}, {0x00, 0x7F, 0x7F}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8A, 0x8A}, {0x00, 0x8B, 0x8B}, {0x00, 0x8C, 0x8C}, + {0x00, 0x8D, 0x8D}, {0x00, 0x8E, 0x8E}, {0x00, 0x8F, 0x8F}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9A, 0x9A}, {0x00, 0x9B, 0x9B}, + {0x00, 0x9C, 0x9C}, {0x00, 0x9D, 0x9D}, {0x00, 0x9E, 0x9E}, + {0x00, 0x9F, 0x9F}, {0x00, 0xA0, 0xA0}, {0x00, 0xA1, 0xA1}, + {0x00, 0xA2, 0xA2}, {0x00, 0xA3, 0xA3}, {0x00, 0xA4, 0xA4}, + {0x00, 0xA5, 0xA5}, {0x00, 0xA6, 0xA6}, {0x00, 0xA7, 0xA7}, + {0x01, 0xB8, 0xA8}, {0x00, 0xA9, 0xA9}, {0x01, 0xBA, 0xAA}, + {0x00, 0xAB, 0xAB}, {0x00, 0xAC, 0xAC}, {0x00, 0xAD, 0xAD}, + {0x00, 0xAE, 0xAE}, {0x01, 0xBF, 0xAF}, {0x00, 0xB0, 0xB0}, + {0x00, 0xB1, 0xB1}, {0x00, 0xB2, 0xB2}, {0x00, 0xB3, 0xB3}, + {0x00, 0xB4, 0xB4}, {0x00, 0xB5, 0xB5}, {0x00, 0xB6, 0xB6}, + {0x00, 0xB7, 0xB7}, {0x00, 0xB8, 0xA8}, {0x00, 0xB9, 0xB9}, + {0x00, 0xBA, 0xAA}, {0x00, 0xBB, 0xBB}, {0x00, 0xBC, 0xBC}, + {0x00, 0xBD, 0xBD}, {0x00, 0xBE, 0xBE}, {0x00, 0xBF, 0xAF}, + {0x01, 0xE0, 0xC0}, {0x01, 0xE1, 0xC1}, {0x01, 0xE2, 0xC2}, + {0x01, 0xE3, 0xC3}, {0x01, 0xE4, 0xC4}, {0x01, 0xE5, 0xC5}, + {0x01, 0xE6, 0xC6}, {0x01, 0xE7, 0xC7}, {0x01, 0xE8, 0xC8}, + {0x01, 0xE9, 0xC9}, {0x01, 0xEA, 0xCA}, {0x01, 0xEB, 0xCB}, + {0x01, 0xEC, 0xCC}, {0x01, 0xED, 0xCD}, {0x01, 0xEE, 0xCE}, + {0x01, 0xEF, 0xCF}, {0x01, 0xF0, 0xD0}, {0x01, 0xF1, 0xD1}, + {0x01, 0xF2, 0xD2}, {0x01, 0xF3, 0xD3}, {0x01, 0xF4, 0xD4}, + {0x01, 0xF5, 0xD5}, {0x01, 0xF6, 0xD6}, {0x00, 0xD7, 0xD7}, + {0x01, 0xF8, 0xD8}, {0x01, 0xF9, 0xD9}, {0x01, 0xFA, 0xDA}, + {0x01, 0xFB, 0xDB}, {0x01, 0xFC, 0xDC}, {0x01, 0xFD, 0xDD}, + {0x01, 0xFE, 0xDE}, {0x00, 0xDF, 0xDF}, {0x00, 0xE0, 0xC0}, + {0x00, 0xE1, 0xC1}, {0x00, 0xE2, 0xC2}, {0x00, 0xE3, 0xC3}, + {0x00, 0xE4, 0xC4}, {0x00, 0xE5, 0xC5}, {0x00, 0xE6, 0xC6}, + {0x00, 0xE7, 0xC7}, {0x00, 0xE8, 0xC8}, {0x00, 0xE9, 0xC9}, + {0x00, 0xEA, 0xCA}, {0x00, 0xEB, 0xCB}, {0x00, 0xEC, 0xCC}, + {0x00, 0xED, 0xCD}, {0x00, 0xEE, 0xCE}, {0x00, 0xEF, 0xCF}, + {0x00, 0xF0, 0xD0}, {0x00, 0xF1, 0xD1}, {0x00, 0xF2, 0xD2}, + {0x00, 0xF3, 0xD3}, {0x00, 0xF4, 0xD4}, {0x00, 0xF5, 0xD5}, + {0x00, 0xF6, 0xD6}, {0x00, 0xF7, 0xF7}, {0x00, 0xF8, 0xD8}, + {0x00, 0xF9, 0xD9}, {0x00, 0xFA, 0xDA}, {0x00, 0xFB, 0xDB}, + {0x00, 0xFC, 0xDC}, {0x00, 0xFD, 0xDD}, {0x00, 0xFE, 0xDE}, + {0x00, 0xFF, 0xFF}}; + +static struct cs_info iso14_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x01, 0xa2, 0xa1}, + {0x00, 0xa2, 0xa1}, {0x00, 0xa3, 0xa3}, {0x01, 0xa5, 0xa4}, + {0x00, 0xa5, 0xa4}, {0x01, 0xa6, 0xab}, {0x00, 0xa7, 0xa7}, + {0x01, 0xb8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x01, 0xba, 0xaa}, + {0x00, 0xab, 0xa6}, {0x01, 0xbc, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x01, 0xff, 0xaf}, {0x01, 0xb1, 0xb0}, + {0x00, 0xb1, 0xb0}, {0x01, 0xb3, 0xb2}, {0x00, 0xb3, 0xb2}, + {0x01, 0xb5, 0xb4}, {0x00, 0xb5, 0xb4}, {0x00, 0xb6, 0xb6}, + {0x01, 0xb9, 0xb7}, {0x00, 0xb8, 0xa8}, {0x00, 0xb9, 0xb6}, + {0x00, 0xba, 0xaa}, {0x01, 0xbf, 0xbb}, {0x00, 0xbc, 0xac}, + {0x01, 0xbe, 0xbd}, {0x00, 0xbe, 0xbd}, {0x00, 0xbf, 0xbb}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x01, 0xf7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xd7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xff}}; + +static struct cs_info iso15_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x01, 0xa8, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa6}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x01, 0xb8, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb4}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x01, 0xbd, 0xbc}, + {0x00, 0xbd, 0xbc}, {0x01, 0xff, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x01, 0xe0, 0xc0}, {0x01, 0xe1, 0xc1}, {0x01, 0xe2, 0xc2}, + {0x01, 0xe3, 0xc3}, {0x01, 0xe4, 0xc4}, {0x01, 0xe5, 0xc5}, + {0x01, 0xe6, 0xc6}, {0x01, 0xe7, 0xc7}, {0x01, 0xe8, 0xc8}, + {0x01, 0xe9, 0xc9}, {0x01, 0xea, 0xca}, {0x01, 0xeb, 0xcb}, + {0x01, 0xec, 0xcc}, {0x01, 0xed, 0xcd}, {0x01, 0xee, 0xce}, + {0x01, 0xef, 0xcf}, {0x01, 0xf0, 0xd0}, {0x01, 0xf1, 0xd1}, + {0x01, 0xf2, 0xd2}, {0x01, 0xf3, 0xd3}, {0x01, 0xf4, 0xd4}, + {0x01, 0xf5, 0xd5}, {0x01, 0xf6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x01, 0xf8, 0xd8}, {0x01, 0xf9, 0xd9}, {0x01, 0xfa, 0xda}, + {0x01, 0xfb, 0xdb}, {0x01, 0xfc, 0xdc}, {0x01, 0xfd, 0xdd}, + {0x01, 0xfe, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xc0}, + {0x00, 0xe1, 0xc1}, {0x00, 0xe2, 0xc2}, {0x00, 0xe3, 0xc3}, + {0x00, 0xe4, 0xc4}, {0x00, 0xe5, 0xc5}, {0x00, 0xe6, 0xc6}, + {0x00, 0xe7, 0xc7}, {0x00, 0xe8, 0xc8}, {0x00, 0xe9, 0xc9}, + {0x00, 0xea, 0xca}, {0x00, 0xeb, 0xcb}, {0x00, 0xec, 0xcc}, + {0x00, 0xed, 0xcd}, {0x00, 0xee, 0xce}, {0x00, 0xef, 0xcf}, + {0x00, 0xf0, 0xd0}, {0x00, 0xf1, 0xd1}, {0x00, 0xf2, 0xd2}, + {0x00, 0xf3, 0xd3}, {0x00, 0xf4, 0xd4}, {0x00, 0xf5, 0xd5}, + {0x00, 0xf6, 0xd6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xd8}, + {0x00, 0xf9, 0xd9}, {0x00, 0xfa, 0xda}, {0x00, 0xfb, 0xdb}, + {0x00, 0xfc, 0xdc}, {0x00, 0xfd, 0xdd}, {0x00, 0xfe, 0xde}, + {0x00, 0xff, 0xbe}}; + +static struct cs_info iscii_devanagari_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +static struct cs_info tis620_tbl[] = { + {0x00, 0x00, 0x00}, {0x00, 0x01, 0x01}, {0x00, 0x02, 0x02}, + {0x00, 0x03, 0x03}, {0x00, 0x04, 0x04}, {0x00, 0x05, 0x05}, + {0x00, 0x06, 0x06}, {0x00, 0x07, 0x07}, {0x00, 0x08, 0x08}, + {0x00, 0x09, 0x09}, {0x00, 0x0a, 0x0a}, {0x00, 0x0b, 0x0b}, + {0x00, 0x0c, 0x0c}, {0x00, 0x0d, 0x0d}, {0x00, 0x0e, 0x0e}, + {0x00, 0x0f, 0x0f}, {0x00, 0x10, 0x10}, {0x00, 0x11, 0x11}, + {0x00, 0x12, 0x12}, {0x00, 0x13, 0x13}, {0x00, 0x14, 0x14}, + {0x00, 0x15, 0x15}, {0x00, 0x16, 0x16}, {0x00, 0x17, 0x17}, + {0x00, 0x18, 0x18}, {0x00, 0x19, 0x19}, {0x00, 0x1a, 0x1a}, + {0x00, 0x1b, 0x1b}, {0x00, 0x1c, 0x1c}, {0x00, 0x1d, 0x1d}, + {0x00, 0x1e, 0x1e}, {0x00, 0x1f, 0x1f}, {0x00, 0x20, 0x20}, + {0x00, 0x21, 0x21}, {0x00, 0x22, 0x22}, {0x00, 0x23, 0x23}, + {0x00, 0x24, 0x24}, {0x00, 0x25, 0x25}, {0x00, 0x26, 0x26}, + {0x00, 0x27, 0x27}, {0x00, 0x28, 0x28}, {0x00, 0x29, 0x29}, + {0x00, 0x2a, 0x2a}, {0x00, 0x2b, 0x2b}, {0x00, 0x2c, 0x2c}, + {0x00, 0x2d, 0x2d}, {0x00, 0x2e, 0x2e}, {0x00, 0x2f, 0x2f}, + {0x00, 0x30, 0x30}, {0x00, 0x31, 0x31}, {0x00, 0x32, 0x32}, + {0x00, 0x33, 0x33}, {0x00, 0x34, 0x34}, {0x00, 0x35, 0x35}, + {0x00, 0x36, 0x36}, {0x00, 0x37, 0x37}, {0x00, 0x38, 0x38}, + {0x00, 0x39, 0x39}, {0x00, 0x3a, 0x3a}, {0x00, 0x3b, 0x3b}, + {0x00, 0x3c, 0x3c}, {0x00, 0x3d, 0x3d}, {0x00, 0x3e, 0x3e}, + {0x00, 0x3f, 0x3f}, {0x00, 0x40, 0x40}, {0x01, 0x61, 0x41}, + {0x01, 0x62, 0x42}, {0x01, 0x63, 0x43}, {0x01, 0x64, 0x44}, + {0x01, 0x65, 0x45}, {0x01, 0x66, 0x46}, {0x01, 0x67, 0x47}, + {0x01, 0x68, 0x48}, {0x01, 0x69, 0x49}, {0x01, 0x6a, 0x4a}, + {0x01, 0x6b, 0x4b}, {0x01, 0x6c, 0x4c}, {0x01, 0x6d, 0x4d}, + {0x01, 0x6e, 0x4e}, {0x01, 0x6f, 0x4f}, {0x01, 0x70, 0x50}, + {0x01, 0x71, 0x51}, {0x01, 0x72, 0x52}, {0x01, 0x73, 0x53}, + {0x01, 0x74, 0x54}, {0x01, 0x75, 0x55}, {0x01, 0x76, 0x56}, + {0x01, 0x77, 0x57}, {0x01, 0x78, 0x58}, {0x01, 0x79, 0x59}, + {0x01, 0x7a, 0x5a}, {0x00, 0x5b, 0x5b}, {0x00, 0x5c, 0x5c}, + {0x00, 0x5d, 0x5d}, {0x00, 0x5e, 0x5e}, {0x00, 0x5f, 0x5f}, + {0x00, 0x60, 0x60}, {0x00, 0x61, 0x41}, {0x00, 0x62, 0x42}, + {0x00, 0x63, 0x43}, {0x00, 0x64, 0x44}, {0x00, 0x65, 0x45}, + {0x00, 0x66, 0x46}, {0x00, 0x67, 0x47}, {0x00, 0x68, 0x48}, + {0x00, 0x69, 0x49}, {0x00, 0x6a, 0x4a}, {0x00, 0x6b, 0x4b}, + {0x00, 0x6c, 0x4c}, {0x00, 0x6d, 0x4d}, {0x00, 0x6e, 0x4e}, + {0x00, 0x6f, 0x4f}, {0x00, 0x70, 0x50}, {0x00, 0x71, 0x51}, + {0x00, 0x72, 0x52}, {0x00, 0x73, 0x53}, {0x00, 0x74, 0x54}, + {0x00, 0x75, 0x55}, {0x00, 0x76, 0x56}, {0x00, 0x77, 0x57}, + {0x00, 0x78, 0x58}, {0x00, 0x79, 0x59}, {0x00, 0x7a, 0x5a}, + {0x00, 0x7b, 0x7b}, {0x00, 0x7c, 0x7c}, {0x00, 0x7d, 0x7d}, + {0x00, 0x7e, 0x7e}, {0x00, 0x7f, 0x7f}, {0x00, 0x80, 0x80}, + {0x00, 0x81, 0x81}, {0x00, 0x82, 0x82}, {0x00, 0x83, 0x83}, + {0x00, 0x84, 0x84}, {0x00, 0x85, 0x85}, {0x00, 0x86, 0x86}, + {0x00, 0x87, 0x87}, {0x00, 0x88, 0x88}, {0x00, 0x89, 0x89}, + {0x00, 0x8a, 0x8a}, {0x00, 0x8b, 0x8b}, {0x00, 0x8c, 0x8c}, + {0x00, 0x8d, 0x8d}, {0x00, 0x8e, 0x8e}, {0x00, 0x8f, 0x8f}, + {0x00, 0x90, 0x90}, {0x00, 0x91, 0x91}, {0x00, 0x92, 0x92}, + {0x00, 0x93, 0x93}, {0x00, 0x94, 0x94}, {0x00, 0x95, 0x95}, + {0x00, 0x96, 0x96}, {0x00, 0x97, 0x97}, {0x00, 0x98, 0x98}, + {0x00, 0x99, 0x99}, {0x00, 0x9a, 0x9a}, {0x00, 0x9b, 0x9b}, + {0x00, 0x9c, 0x9c}, {0x00, 0x9d, 0x9d}, {0x00, 0x9e, 0x9e}, + {0x00, 0x9f, 0x9f}, {0x00, 0xa0, 0xa0}, {0x00, 0xa1, 0xa1}, + {0x00, 0xa2, 0xa2}, {0x00, 0xa3, 0xa3}, {0x00, 0xa4, 0xa4}, + {0x00, 0xa5, 0xa5}, {0x00, 0xa6, 0xa6}, {0x00, 0xa7, 0xa7}, + {0x00, 0xa8, 0xa8}, {0x00, 0xa9, 0xa9}, {0x00, 0xaa, 0xaa}, + {0x00, 0xab, 0xab}, {0x00, 0xac, 0xac}, {0x00, 0xad, 0xad}, + {0x00, 0xae, 0xae}, {0x00, 0xaf, 0xaf}, {0x00, 0xb0, 0xb0}, + {0x00, 0xb1, 0xb1}, {0x00, 0xb2, 0xb2}, {0x00, 0xb3, 0xb3}, + {0x00, 0xb4, 0xb4}, {0x00, 0xb5, 0xb5}, {0x00, 0xb6, 0xb6}, + {0x00, 0xb7, 0xb7}, {0x00, 0xb8, 0xb8}, {0x00, 0xb9, 0xb9}, + {0x00, 0xba, 0xba}, {0x00, 0xbb, 0xbb}, {0x00, 0xbc, 0xbc}, + {0x00, 0xbd, 0xbd}, {0x00, 0xbe, 0xbe}, {0x00, 0xbf, 0xbf}, + {0x00, 0xc0, 0xc0}, {0x00, 0xc1, 0xc1}, {0x00, 0xc2, 0xc2}, + {0x00, 0xc3, 0xc3}, {0x00, 0xc4, 0xc4}, {0x00, 0xc5, 0xc5}, + {0x00, 0xc6, 0xc6}, {0x00, 0xc7, 0xc7}, {0x00, 0xc8, 0xc8}, + {0x00, 0xc9, 0xc9}, {0x00, 0xca, 0xca}, {0x00, 0xcb, 0xcb}, + {0x00, 0xcc, 0xcc}, {0x00, 0xcd, 0xcd}, {0x00, 0xce, 0xce}, + {0x00, 0xcf, 0xcf}, {0x00, 0xd0, 0xd0}, {0x00, 0xd1, 0xd1}, + {0x00, 0xd2, 0xd2}, {0x00, 0xd3, 0xd3}, {0x00, 0xd4, 0xd4}, + {0x00, 0xd5, 0xd5}, {0x00, 0xd6, 0xd6}, {0x00, 0xd7, 0xd7}, + {0x00, 0xd8, 0xd8}, {0x00, 0xd9, 0xd9}, {0x00, 0xda, 0xda}, + {0x00, 0xdb, 0xdb}, {0x00, 0xdc, 0xdc}, {0x00, 0xdd, 0xdd}, + {0x00, 0xde, 0xde}, {0x00, 0xdf, 0xdf}, {0x00, 0xe0, 0xe0}, + {0x00, 0xe1, 0xe1}, {0x00, 0xe2, 0xe2}, {0x00, 0xe3, 0xe3}, + {0x00, 0xe4, 0xe4}, {0x00, 0xe5, 0xe5}, {0x00, 0xe6, 0xe6}, + {0x00, 0xe7, 0xe7}, {0x00, 0xe8, 0xe8}, {0x00, 0xe9, 0xe9}, + {0x00, 0xea, 0xea}, {0x00, 0xeb, 0xeb}, {0x00, 0xec, 0xec}, + {0x00, 0xed, 0xed}, {0x00, 0xee, 0xee}, {0x00, 0xef, 0xef}, + {0x00, 0xf0, 0xf0}, {0x00, 0xf1, 0xf1}, {0x00, 0xf2, 0xf2}, + {0x00, 0xf3, 0xf3}, {0x00, 0xf4, 0xf4}, {0x00, 0xf5, 0xf5}, + {0x00, 0xf6, 0xf6}, {0x00, 0xf7, 0xf7}, {0x00, 0xf8, 0xf8}, + {0x00, 0xf9, 0xf9}, {0x00, 0xfa, 0xfa}, {0x00, 0xfb, 0xfb}, + {0x00, 0xfc, 0xfc}, {0x00, 0xfd, 0xfd}, {0x00, 0xfe, 0xfe}, + {0x00, 0xff, 0xff}}; + +struct enc_entry { + const char* enc_name; + struct cs_info* cs_table; +}; + +static struct enc_entry encds[] = { + {"iso88591", iso1_tbl}, // ISO-8859-1 + {"iso88592", iso2_tbl}, // ISO-8859-2 + {"iso88593", iso3_tbl}, // ISO-8859-3 + {"iso88594", iso4_tbl}, // ISO-8859-4 + {"iso88595", iso5_tbl}, // ISO-8859-5 + {"iso88596", iso6_tbl}, // ISO-8859-6 + {"iso88597", iso7_tbl}, // ISO-8859-7 + {"iso88598", iso8_tbl}, // ISO-8859-8 + {"iso88599", iso9_tbl}, // ISO-8859-9 + {"iso885910", iso10_tbl}, // ISO-8859-10 + {"tis620", tis620_tbl}, // TIS-620/ISO-8859-11 + {"tis6202533", tis620_tbl}, // TIS-620/ISO-8859-11 + {"iso885911", tis620_tbl}, // TIS-620/ISO-8859-11 + {"iso885913", iso13_tbl}, // ISO-8859-13 + {"iso885914", iso14_tbl}, // ISO-8859-14 + {"iso885915", iso15_tbl}, // ISO-8859-15 + {"koi8r", koi8r_tbl}, // KOI8-R + {"koi8u", koi8u_tbl}, // KOI8-U + {"cp1251", cp1251_tbl}, // CP-1251 + {"microsoftcp1251", cp1251_tbl}, // microsoft-cp1251 + {"xisciias", iscii_devanagari_tbl}, // x-iscii-as + {"isciidevanagari", iscii_devanagari_tbl} // ISCII-DEVANAGARI +}; + +/* map to lower case and remove non alphanumeric chars */ +static void toAsciiLowerAndRemoveNonAlphanumeric(const char* pName, + char* pBuf) { + while (*pName) { + /* A-Z */ + if ((*pName >= 0x41) && (*pName <= 0x5A)) { + *pBuf = (*pName) + 0x20; /* toAsciiLower */ + pBuf++; + } + /* a-z, 0-9 */ + else if (((*pName >= 0x61) && (*pName <= 0x7A)) || + ((*pName >= 0x30) && (*pName <= 0x39))) { + *pBuf = *pName; + pBuf++; + } + + pName++; + } + + *pBuf = '\0'; +} + +struct cs_info* get_current_cs(const char* es) { + char* normalized_encoding = new char[strlen(es) + 1]; + toAsciiLowerAndRemoveNonAlphanumeric(es, normalized_encoding); + + struct cs_info* ccs = NULL; + int n = sizeof(encds) / sizeof(encds[0]); + for (int i = 0; i < n; i++) { + if (strcmp(normalized_encoding, encds[i].enc_name) == 0) { + ccs = encds[i].cs_table; + break; + } + } + + delete[] normalized_encoding; + + if (!ccs) { + HUNSPELL_WARNING(stderr, + "error: unknown encoding %s: using %s as fallback\n", es, + encds[0].enc_name); + ccs = encds[0].cs_table; + } + + return ccs; +} +#else +// XXX This function was rewritten for mozilla. Instead of storing the +// conversion tables static in this file, create them when needed +// with help the mozilla backend. +struct cs_info* get_current_cs(const char* es) { + struct cs_info* ccs = new cs_info[256]; + // Initialze the array with dummy data so that we wouldn't need + // to return null in case of failures. + for (int i = 0; i <= 0xff; ++i) { + ccs[i].ccase = false; + ccs[i].clower = i; + ccs[i].cupper = i; + } + + nsCOMPtr<nsIUnicodeEncoder> encoder; + nsCOMPtr<nsIUnicodeDecoder> decoder; + + nsresult rv; + + nsAutoCString label(es); + nsAutoCString encoding; + if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { + return ccs; + } + encoder = EncodingUtils::EncoderForEncoding(encoding); + decoder = EncodingUtils::DecoderForEncoding(encoding); + encoder->SetOutputErrorBehavior(encoder->kOnError_Signal, nullptr, '?'); + decoder->SetInputErrorBehavior(decoder->kOnError_Signal); + + for (unsigned int i = 0; i <= 0xff; ++i) { + bool success = false; + // We want to find the upper/lowercase equivalents of each byte + // in this 1-byte character encoding. Call our encoding/decoding + // APIs separately for each byte since they may reject some of the + // bytes, and we want to handle errors separately for each byte. + char lower, upper; + do { + if (i == 0) + break; + const char source = char(i); + char16_t uni, uniCased; + int32_t charLength = 1, uniLength = 1; + + rv = decoder->Convert(&source, &charLength, &uni, &uniLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + uniCased = ToLowerCase(uni); + rv = encoder->Convert(&uniCased, &uniLength, &lower, &charLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + + uniCased = ToUpperCase(uni); + rv = encoder->Convert(&uniCased, &uniLength, &upper, &charLength); + // Explicitly check NS_OK because we don't want to allow + // NS_OK_UDEC_MOREOUTPUT or NS_OK_UDEC_MOREINPUT. + if (rv != NS_OK || charLength != 1 || uniLength != 1) + break; + + success = true; + } while (0); + + if (success) { + ccs[i].cupper = upper; + ccs[i].clower = lower; + } else { + ccs[i].cupper = i; + ccs[i].clower = i; + } + + if (ccs[i].clower != (unsigned char)i) + ccs[i].ccase = true; + else + ccs[i].ccase = false; + } + + return ccs; +} +#endif + +// primitive isalpha() replacement for tokenization +char* get_casechars(const char* enc) { + struct cs_info* csconv = get_current_cs(enc); + char expw[MAXLNLEN]; + char* p = expw; + for (int i = 0; i <= 255; i++) { + if (cupper(csconv, i) != clower(csconv, i)) { + *p = static_cast<char>(i); + p++; + } + } + *p = '\0'; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif + return mystrdup(expw); +} + +// language to encoding default map + +struct lang_map { + const char* lang; + int num; +}; + +static struct lang_map lang2enc[] = + {{"ar", LANG_ar}, {"az", LANG_az}, + {"az_AZ", LANG_az}, // for back-compatibility + {"bg", LANG_bg}, {"ca", LANG_ca}, + {"cs", LANG_cs}, {"da", LANG_da}, + {"de", LANG_de}, {"el", LANG_el}, + {"en", LANG_en}, {"es", LANG_es}, + {"eu", LANG_eu}, {"gl", LANG_gl}, + {"fr", LANG_fr}, {"hr", LANG_hr}, + {"hu", LANG_hu}, {"hu_HU", LANG_hu}, // for back-compatibility + {"it", LANG_it}, {"la", LANG_la}, + {"lv", LANG_lv}, {"nl", LANG_nl}, + {"pl", LANG_pl}, {"pt", LANG_pt}, + {"sv", LANG_sv}, {"tr", LANG_tr}, + {"tr_TR", LANG_tr}, // for back-compatibility + {"ru", LANG_ru}, {"uk", LANG_uk}}; + +int get_lang_num(const char* lang) { + int n = sizeof(lang2enc) / sizeof(lang2enc[0]); + for (int i = 0; i < n; i++) { + if (strcmp(lang, lang2enc[i].lang) == 0) { + return lang2enc[i].num; + } + } + return LANG_xx; +} + +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT +int initialize_utf_tbl() { + utf_tbl_count++; + if (utf_tbl) + return 0; + utf_tbl = (unicode_info2*)malloc(CONTSIZE * sizeof(unicode_info2)); + if (utf_tbl) { + size_t j; + for (j = 0; j < CONTSIZE; j++) { + utf_tbl[j].cletter = 0; + utf_tbl[j].clower = (unsigned short)j; + utf_tbl[j].cupper = (unsigned short)j; + } + for (j = 0; j < UTF_LST_LEN; j++) { + utf_tbl[utf_lst[j].c].cletter = 1; + utf_tbl[utf_lst[j].c].clower = utf_lst[j].clower; + utf_tbl[utf_lst[j].c].cupper = utf_lst[j].cupper; + } + } else + return 1; + return 0; +} +#endif +#endif + +void free_utf_tbl() { + if (utf_tbl_count > 0) + utf_tbl_count--; + if (utf_tbl && (utf_tbl_count == 0)) { + free(utf_tbl); + utf_tbl = NULL; + } +} + +unsigned short unicodetoupper(unsigned short c, int langnum) { + // In Azeri and Turkish, I and i dictinct letters: + // There are a dotless lower case i pair of upper `I', + // and an upper I with dot pair of lower `i'. + if (c == 0x0069 && ((langnum == LANG_az) || (langnum == LANG_tr))) + return 0x0130; +#ifdef OPENOFFICEORG + return static_cast<unsigned short>(u_toupper(c)); +#else +#ifdef MOZILLA_CLIENT + return ToUpperCase((char16_t)c); +#else + return (utf_tbl) ? utf_tbl[c].cupper : c; +#endif +#endif +} + +unsigned short unicodetolower(unsigned short c, int langnum) { + // In Azeri and Turkish, I and i dictinct letters: + // There are a dotless lower case i pair of upper `I', + // and an upper I with dot pair of lower `i'. + if (c == 0x0049 && ((langnum == LANG_az) || (langnum == LANG_tr))) + return 0x0131; +#ifdef OPENOFFICEORG + return static_cast<unsigned short>(u_tolower(c)); +#else +#ifdef MOZILLA_CLIENT + return ToLowerCase((char16_t)c); +#else + return (utf_tbl) ? utf_tbl[c].clower : c; +#endif +#endif +} + +int unicodeisalpha(unsigned short c) { +#ifdef OPENOFFICEORG + return u_isalpha(c); +#else + return (utf_tbl) ? utf_tbl[c].cletter : 0; +#endif +} + +/* get type of capitalization */ +int get_captype(const std::string& word, cs_info* csconv) { + // now determine the capitalization type of the first nl letters + size_t ncap = 0; + size_t nneutral = 0; + size_t firstcap = 0; + if (csconv == NULL) + return NOCAP; + for (std::string::const_iterator q = word.begin(); q != word.end(); ++q) { + unsigned char nIndex = static_cast<unsigned char>(*q); + if (ccase(csconv, nIndex)) + ncap++; + if (cupper(csconv, nIndex) == clower(csconv, nIndex)) + nneutral++; + } + if (ncap) { + unsigned char nIndex = static_cast<unsigned char>(word[0]); + firstcap = csconv[nIndex].ccase; + } + + // now finally set the captype + if (ncap == 0) { + return NOCAP; + } else if ((ncap == 1) && firstcap) { + return INITCAP; + } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { + return ALLCAP; + } else if ((ncap > 1) && firstcap) { + return HUHINITCAP; + } + return HUHCAP; +} + +int get_captype_utf8(const std::vector<w_char>& word, int langnum) { + // now determine the capitalization type of the first nl letters + size_t ncap = 0; + size_t nneutral = 0; + size_t firstcap = 0; + for (size_t i = 0; i < word.size(); ++i) { + unsigned short idx = (word[i].h << 8) + word[i].l; + if (idx != unicodetolower(idx, langnum)) + ncap++; + if (unicodetoupper(idx, langnum) == unicodetolower(idx, langnum)) + nneutral++; + } + if (ncap) { + unsigned short idx = (word[0].h << 8) + word[0].l; + firstcap = (idx != unicodetolower(idx, langnum)); + } + + // now finally set the captype + if (ncap == 0) { + return NOCAP; + } else if ((ncap == 1) && firstcap) { + return INITCAP; + } else if ((ncap == word.size()) || ((ncap + nneutral) == word.size())) { + return ALLCAP; + } else if ((ncap > 1) && firstcap) { + return HUHINITCAP; + } + return HUHCAP; +} + +// strip all ignored characters in the string +size_t remove_ignored_chars_utf(std::string& word, + const std::vector<w_char>& ignored_chars) { + std::vector<w_char> w; + std::vector<w_char> w2; + u8_u16(w, word); + + for (size_t i = 0; i < w.size(); ++i) { + if (!std::binary_search(ignored_chars.begin(), + ignored_chars.end(), + w[i])) { + w2.push_back(w[i]); + } + } + + u16_u8(word, w2); + return w2.size(); +} + +namespace { +class is_any_of { + public: + is_any_of(const std::string& in) : chars(in) {} + + bool operator()(char c) { return chars.find(c) != std::string::npos; } + + private: + std::string chars; +}; +} + +// strip all ignored characters in the string +size_t remove_ignored_chars(std::string& word, + const std::string& ignored_chars) { + word.erase( + std::remove_if(word.begin(), word.end(), is_any_of(ignored_chars)), + word.end()); + return word.size(); +} + +int parse_string(char* line, char** out, int ln) { + char* tp = line; + char* piece; + int i = 0; + int np = 0; + if (*out) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions\n", ln); + return 1; + } + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + *out = mystrdup(piece); + if (!*out) + return 1; + np++; + break; + } + default: + break; + } + i++; + } + // free(piece); + piece = mystrsep(&tp, 0); + } + if (np != 2) { + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", ln); + return 1; + } + return 0; +} + +bool parse_array(char* line, + char** out, + std::vector<w_char>& out_utf16, + int utf8, + int ln) { + if (parse_string(line, out, ln)) + return false; + if (utf8) { + u8_u16(out_utf16, *out); + std::sort(out_utf16.begin(), out_utf16.end()); + } + return true; +} diff --git a/extensions/spellcheck/hunspell/src/csutil.hxx b/extensions/spellcheck/hunspell/src/csutil.hxx new file mode 100644 index 000000000..ce7091df5 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/csutil.hxx @@ -0,0 +1,325 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __CSUTILHXX__ +#define __CSUTILHXX__ + +#include "hunvisapi.h" + +// First some base level utility routines + +#include <string> +#include <vector> +#include <string.h> +#include "w_char.hxx" +#include "htypes.hxx" + +#ifdef MOZILLA_CLIENT +#include "nscore.h" // for mozalloc headers +#endif + +// casing +#define NOCAP 0 +#define INITCAP 1 +#define ALLCAP 2 +#define HUHCAP 3 +#define HUHINITCAP 4 + +// default encoding and keystring +#define SPELL_ENCODING "ISO8859-1" +#define SPELL_KEYSTRING "qwertyuiop|asdfghjkl|zxcvbnm" + +// default morphological fields +#define MORPH_STEM "st:" +#define MORPH_ALLOMORPH "al:" +#define MORPH_POS "po:" +#define MORPH_DERI_PFX "dp:" +#define MORPH_INFL_PFX "ip:" +#define MORPH_TERM_PFX "tp:" +#define MORPH_DERI_SFX "ds:" +#define MORPH_INFL_SFX "is:" +#define MORPH_TERM_SFX "ts:" +#define MORPH_SURF_PFX "sp:" +#define MORPH_FREQ "fr:" +#define MORPH_PHON "ph:" +#define MORPH_HYPH "hy:" +#define MORPH_PART "pa:" +#define MORPH_FLAG "fl:" +#define MORPH_HENTRY "_H:" +#define MORPH_TAG_LEN strlen(MORPH_STEM) + +#define MSEP_FLD ' ' +#define MSEP_REC '\n' +#define MSEP_ALT '\v' + +// default flags +#define DEFAULTFLAGS 65510 +#define FORBIDDENWORD 65510 +#define ONLYUPCASEFLAG 65511 + +// fopen or optional _wfopen to fix long pathname problem of WIN32 +LIBHUNSPELL_DLL_EXPORTED FILE* myfopen(const char* path, const char* mode); + +// convert UTF-16 characters to UTF-8 +LIBHUNSPELL_DLL_EXPORTED std::string& u16_u8(std::string& dest, + const std::vector<w_char>& src); + +// convert UTF-8 characters to UTF-16 +LIBHUNSPELL_DLL_EXPORTED int u8_u16(std::vector<w_char>& dest, + const std::string& src); + +// remove end of line char(s) +LIBHUNSPELL_DLL_EXPORTED void mychomp(char* s); + +// duplicate string +LIBHUNSPELL_DLL_EXPORTED char* mystrdup(const char* s); + +// strcat for limited length destination string +LIBHUNSPELL_DLL_EXPORTED char* mystrcat(char* dest, const char* st, int max); + +// parse into tokens with char delimiter +LIBHUNSPELL_DLL_EXPORTED char* mystrsep(char** sptr, const char delim); + +// replace pat by rep in word and return word +LIBHUNSPELL_DLL_EXPORTED char* mystrrep(char* word, + const char* pat, + const char* rep); +LIBHUNSPELL_DLL_EXPORTED std::string& mystrrep(std::string& str, + const std::string& search, + const std::string& replace); + +// append s to ends of every lines in text +LIBHUNSPELL_DLL_EXPORTED std::string& strlinecat(std::string& str, + const std::string& apd); + +// tokenize into lines with new line +LIBHUNSPELL_DLL_EXPORTED int line_tok(const char* text, + char*** lines, + char breakchar); + +// tokenize into lines with new line and uniq in place +LIBHUNSPELL_DLL_EXPORTED char* line_uniq(char* text, char breakchar); +LIBHUNSPELL_DLL_EXPORTED char* line_uniq_app(char** text, char breakchar); + +// reverse word +LIBHUNSPELL_DLL_EXPORTED size_t reverseword(std::string& word); + +// reverse word +LIBHUNSPELL_DLL_EXPORTED size_t reverseword_utf(std::string&); + +// remove duplicates +LIBHUNSPELL_DLL_EXPORTED int uniqlist(char** list, int n); + +// free character array list +LIBHUNSPELL_DLL_EXPORTED void freelist(char*** list, int n); + +// character encoding information +struct cs_info { + unsigned char ccase; + unsigned char clower; + unsigned char cupper; +}; + +LIBHUNSPELL_DLL_EXPORTED int initialize_utf_tbl(); +LIBHUNSPELL_DLL_EXPORTED void free_utf_tbl(); +LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetoupper(unsigned short c, + int langnum); +LIBHUNSPELL_DLL_EXPORTED w_char upper_utf(w_char u, int langnum); +LIBHUNSPELL_DLL_EXPORTED w_char lower_utf(w_char u, int langnum); +LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetolower(unsigned short c, + int langnum); +LIBHUNSPELL_DLL_EXPORTED int unicodeisalpha(unsigned short c); + +LIBHUNSPELL_DLL_EXPORTED struct cs_info* get_current_cs(const char* es); + +// get language identifiers of language codes +LIBHUNSPELL_DLL_EXPORTED int get_lang_num(const char* lang); + +// get characters of the given 8bit encoding with lower- and uppercase forms +LIBHUNSPELL_DLL_EXPORTED char* get_casechars(const char* enc); + +// convert std::string to all caps +LIBHUNSPELL_DLL_EXPORTED std::string& mkallcap(std::string& s, + const struct cs_info* csconv); + +// convert null terminated string to all little +LIBHUNSPELL_DLL_EXPORTED std::string& mkallsmall(std::string& s, + const struct cs_info* csconv); + +// convert first letter of string to little +LIBHUNSPELL_DLL_EXPORTED std::string& mkinitsmall(std::string& s, + const struct cs_info* csconv); + +// convert first letter of string to capital +LIBHUNSPELL_DLL_EXPORTED std::string& mkinitcap(std::string& s, + const struct cs_info* csconv); + +// convert first letter of UTF-8 string to capital +LIBHUNSPELL_DLL_EXPORTED std::vector<w_char>& +mkinitcap_utf(std::vector<w_char>& u, int langnum); + +// convert UTF-8 string to little +LIBHUNSPELL_DLL_EXPORTED std::vector<w_char>& +mkallsmall_utf(std::vector<w_char>& u, int langnum); + +// convert first letter of UTF-8 string to little +LIBHUNSPELL_DLL_EXPORTED std::vector<w_char>& +mkinitsmall_utf(std::vector<w_char>& u, int langnum); + +// convert UTF-8 string to capital +LIBHUNSPELL_DLL_EXPORTED std::vector<w_char>& +mkallcap_utf(std::vector<w_char>& u, int langnum); + +// get type of capitalization +LIBHUNSPELL_DLL_EXPORTED int get_captype(const std::string& q, cs_info*); + +// get type of capitalization (UTF-8) +LIBHUNSPELL_DLL_EXPORTED int get_captype_utf8(const std::vector<w_char>& q, int langnum); + +// strip all ignored characters in the string +LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars_utf( + std::string& word, + const std::vector<w_char>& ignored_chars); + +// strip all ignored characters in the string +LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars( + std::string& word, + const std::string& ignored_chars); + +LIBHUNSPELL_DLL_EXPORTED int parse_string(char* line, char** out, int ln); + +LIBHUNSPELL_DLL_EXPORTED bool parse_array(char* line, + char** out, + std::vector<w_char>& out_utf16, + int utf8, + int ln); + +LIBHUNSPELL_DLL_EXPORTED int fieldlen(const char* r); + +LIBHUNSPELL_DLL_EXPORTED bool copy_field(std::string& dest, + const std::string& morph, + const std::string& var); + +LIBHUNSPELL_DLL_EXPORTED int morphcmp(const char* s, const char* t); + +LIBHUNSPELL_DLL_EXPORTED int get_sfxcount(const char* morph); + +// conversion function for protected memory +LIBHUNSPELL_DLL_EXPORTED void store_pointer(char* dest, char* source); + +// conversion function for protected memory +LIBHUNSPELL_DLL_EXPORTED char* get_stored_pointer(const char* s); + +// hash entry macros +LIBHUNSPELL_DLL_EXPORTED inline char* HENTRY_DATA(struct hentry* h) { + char* ret; + if (!h->var) + ret = NULL; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +LIBHUNSPELL_DLL_EXPORTED inline const char* HENTRY_DATA( + const struct hentry* h) { + const char* ret; + if (!h->var) + ret = NULL; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +// NULL-free version for warning-free OOo build +LIBHUNSPELL_DLL_EXPORTED inline const char* HENTRY_DATA2( + const struct hentry* h) { + const char* ret; + if (!h->var) + ret = ""; + else if (h->var & H_OPT_ALIASM) + ret = get_stored_pointer(HENTRY_WORD(h) + h->blen + 1); + else + ret = HENTRY_WORD(h) + h->blen + 1; + return ret; +} + +LIBHUNSPELL_DLL_EXPORTED inline char* HENTRY_FIND(struct hentry* h, + const char* p) { + return (HENTRY_DATA(h) ? strstr(HENTRY_DATA(h), p) : NULL); +} + +#endif diff --git a/extensions/spellcheck/hunspell/src/filemgr.cxx b/extensions/spellcheck/hunspell/src/filemgr.cxx new file mode 100644 index 000000000..2218bc79e --- /dev/null +++ b/extensions/spellcheck/hunspell/src/filemgr.cxx @@ -0,0 +1,120 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "filemgr.hxx" +#include "csutil.hxx" + +int FileMgr::fail(const char* err, const char* par) { + fprintf(stderr, err, par); + return -1; +} + +FileMgr::FileMgr(const char* file, const char* key) : hin(NULL), linenum(0) { + in[0] = '\0'; + + fin = myfopen(file, "r"); + if (!fin) { + // check hzipped file + std::string st(file); + st.append(HZIP_EXTENSION); + hin = new Hunzip(st.c_str(), key); + } + if (!fin && !hin) + fail(MSG_OPEN, file); +} + +FileMgr::~FileMgr() { + if (fin) + fclose(fin); + if (hin) + delete hin; +} + +char* FileMgr::getline() { + const char* l; + linenum++; + if (fin) + return fgets(in, BUFSIZE - 1, fin); + if (hin && ((l = hin->getline()) != NULL)) + return strcpy(in, l); + linenum--; + return NULL; +} + +int FileMgr::getlinenum() { + return linenum; +} diff --git a/extensions/spellcheck/hunspell/src/filemgr.hxx b/extensions/spellcheck/hunspell/src/filemgr.hxx new file mode 100644 index 000000000..8b69931dd --- /dev/null +++ b/extensions/spellcheck/hunspell/src/filemgr.hxx @@ -0,0 +1,101 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* file manager class - read lines of files [filename] OR [filename.hz] */ +#ifndef _FILEMGR_HXX_ +#define _FILEMGR_HXX_ + +#include "hunvisapi.h" + +#include "hunzip.hxx" +#include <stdio.h> + +class LIBHUNSPELL_DLL_EXPORTED FileMgr { + private: + FileMgr(const FileMgr&); + FileMgr& operator=(const FileMgr&); + + protected: + FILE* fin; + Hunzip* hin; + char in[BUFSIZE + 50]; // input buffer + int fail(const char* err, const char* par); + int linenum; + + public: + FileMgr(const char* filename, const char* key = NULL); + ~FileMgr(); + char* getline(); + int getlinenum(); +}; +#endif diff --git a/extensions/spellcheck/hunspell/src/hashmgr.cxx b/extensions/spellcheck/hunspell/src/hashmgr.cxx new file mode 100644 index 000000000..c3cd95420 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hashmgr.cxx @@ -0,0 +1,1147 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <limits> +#include <sstream> + +#include "hashmgr.hxx" +#include "csutil.hxx" +#include "atypes.hxx" + +// build a hash table from a munched word list + +HashMgr::HashMgr(const char* tpath, const char* apath, const char* key) + : tablesize(0), + tableptr(NULL), + flag_mode(FLAG_CHAR), + complexprefixes(0), + utf8(0), + forbiddenword(FORBIDDENWORD) // forbidden word signing flag + , + numaliasf(0), + aliasf(NULL), + aliasflen(0), + numaliasm(0), + aliasm(NULL) { + langnum = 0; + lang = NULL; + enc = NULL; + csconv = 0; + ignorechars = NULL; + load_config(apath, key); + int ec = load_tables(tpath, key); + if (ec) { + /* error condition - what should we do here */ + HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n", ec); + if (tableptr) { + free(tableptr); + tableptr = NULL; + } + tablesize = 0; + } +} + +HashMgr::~HashMgr() { + if (tableptr) { + // now pass through hash table freeing up everything + // go through column by column of the table + for (int i = 0; i < tablesize; i++) { + struct hentry* pt = tableptr[i]; + struct hentry* nt = NULL; + while (pt) { + nt = pt->next; + if (pt->astr && + (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) + free(pt->astr); + free(pt); + pt = nt; + } + } + free(tableptr); + } + tablesize = 0; + + if (aliasf) { + for (int j = 0; j < (numaliasf); j++) + free(aliasf[j]); + free(aliasf); + aliasf = NULL; + if (aliasflen) { + free(aliasflen); + aliasflen = NULL; + } + } + if (aliasm) { + for (int j = 0; j < (numaliasm); j++) + free(aliasm[j]); + free(aliasm); + aliasm = NULL; + } + +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + if (utf8) + free_utf_tbl(); +#endif +#endif + + if (enc) + free(enc); + if (lang) + free(lang); + + if (ignorechars) + free(ignorechars); + +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +// lookup a root word in the hashtable + +struct hentry* HashMgr::lookup(const char* word) const { + struct hentry* dp; + if (tableptr) { + dp = tableptr[hash(word)]; + if (!dp) + return NULL; + for (; dp != NULL; dp = dp->next) { + if (strcmp(word, dp->word) == 0) + return dp; + } + } + return NULL; +} + +// add a word to the hash table (private) +int HashMgr::add_word(const char* word, + int wbl, + int wcl, + unsigned short* aff, + int al, + const char* desc, + bool onlyupcase) { + + std::string *word_copy = NULL; + std::string *desc_copy = NULL; + if (ignorechars || complexprefixes) { + word_copy = new std::string(word, wbl); + + if (ignorechars != NULL) { + if (utf8) { + wcl = remove_ignored_chars_utf(*word_copy, ignorechars_utf16); + } else { + remove_ignored_chars(*word_copy, ignorechars); + } + } + + if (complexprefixes) { + if (utf8) + wcl = reverseword_utf(*word_copy); + else + reverseword(*word_copy); + + if (desc && !aliasm) { + desc_copy = new std::string(desc); + + if (complexprefixes) { + if (utf8) + reverseword_utf(*desc_copy); + else + reverseword(*desc_copy); + } + desc = desc_copy->c_str(); + } + } + + wbl = word_copy->size(); + word = word_copy->c_str(); + } + + bool upcasehomonym = false; + int descl = desc ? (aliasm ? sizeof(char*) : strlen(desc) + 1) : 0; + // variable-length hash record with word and optional fields + struct hentry* hp = + (struct hentry*)malloc(sizeof(struct hentry) + wbl + descl); + if (!hp) { + delete desc_copy; + delete word_copy; + return 1; + } + + char* hpw = hp->word; + strcpy(hpw, word); + + int i = hash(hpw); + + hp->blen = (unsigned char)wbl; + hp->clen = (unsigned char)wcl; + hp->alen = (short)al; + hp->astr = aff; + hp->next = NULL; + hp->next_homonym = NULL; + + // store the description string or its pointer + if (desc) { + hp->var = H_OPT; + if (aliasm) { + hp->var += H_OPT_ALIASM; + store_pointer(hpw + wbl + 1, get_aliasm(atoi(desc))); + } else { + strcpy(hpw + wbl + 1, desc); + } + if (strstr(HENTRY_DATA(hp), MORPH_PHON)) + hp->var += H_OPT_PHON; + } else + hp->var = 0; + + struct hentry* dp = tableptr[i]; + if (!dp) { + tableptr[i] = hp; + delete desc_copy; + delete word_copy; + return 0; + } + while (dp->next != NULL) { + if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) { + // remove hidden onlyupcase homonym + if (!onlyupcase) { + if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { + free(dp->astr); + dp->astr = hp->astr; + dp->alen = hp->alen; + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else { + dp->next_homonym = hp; + } + } else { + upcasehomonym = true; + } + } + dp = dp->next; + } + if (strcmp(hp->word, dp->word) == 0) { + // remove hidden onlyupcase homonym + if (!onlyupcase) { + if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { + free(dp->astr); + dp->astr = hp->astr; + dp->alen = hp->alen; + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else { + dp->next_homonym = hp; + } + } else { + upcasehomonym = true; + } + } + if (!upcasehomonym) { + dp->next = hp; + } else { + // remove hidden onlyupcase homonym + if (hp->astr) + free(hp->astr); + free(hp); + } + + delete desc_copy; + delete word_copy; + return 0; +} + +int HashMgr::add_hidden_capitalized_word(const std::string& word, + int wcl, + unsigned short* flags, + int flagslen, + char* dp, + int captype) { + if (flags == NULL) + flagslen = 0; + + // add inner capitalized forms to handle the following allcap forms: + // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG + // Allcaps with suffixes: CIA's -> CIA'S + if (((captype == HUHCAP) || (captype == HUHINITCAP) || + ((captype == ALLCAP) && (flagslen != 0))) && + !((flagslen != 0) && TESTAFF(flags, forbiddenword, flagslen))) { + unsigned short* flags2 = + (unsigned short*)malloc(sizeof(unsigned short) * (flagslen + 1)); + if (!flags2) + return 1; + if (flagslen) + memcpy(flags2, flags, flagslen * sizeof(unsigned short)); + flags2[flagslen] = ONLYUPCASEFLAG; + if (utf8) { + std::string st; + std::vector<w_char> w; + u8_u16(w, word); + mkallsmall_utf(w, langnum); + mkinitcap_utf(w, langnum); + u16_u8(st, w); + return add_word(st.c_str(), st.size(), wcl, flags2, flagslen + 1, dp, true); + } else { + std::string new_word(word); + mkallsmall(new_word, csconv); + mkinitcap(new_word, csconv); + int ret = add_word(new_word.c_str(), new_word.size(), wcl, flags2, flagslen + 1, dp, true); + return ret; + } + } + return 0; +} + +// detect captype and modify word length for UTF-8 encoding +int HashMgr::get_clen_and_captype(const std::string& word, int* captype) { + int len; + if (utf8) { + std::vector<w_char> dest_utf; + len = u8_u16(dest_utf, word); + *captype = get_captype_utf8(dest_utf, langnum); + } else { + len = word.size(); + *captype = get_captype(word, csconv); + } + return len; +} + +// remove word (personal dictionary function for standalone applications) +int HashMgr::remove(const char* word) { + struct hentry* dp = lookup(word); + while (dp) { + if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { + unsigned short* flags = + (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen + 1)); + if (!flags) + return 1; + for (int i = 0; i < dp->alen; i++) + flags[i] = dp->astr[i]; + flags[dp->alen] = forbiddenword; + dp->astr = flags; + dp->alen++; + std::sort(flags, flags + dp->alen); + } + dp = dp->next_homonym; + } + return 0; +} + +/* remove forbidden flag to add a personal word to the hash */ +int HashMgr::remove_forbidden_flag(const std::string& word) { + struct hentry* dp = lookup(word.c_str()); + if (!dp) + return 1; + while (dp) { + if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { + if (dp->alen == 1) + dp->alen = 0; // XXX forbidden words of personal dic. + else { + unsigned short* flags2 = + (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen - 1)); + if (!flags2) + return 1; + int i, j = 0; + for (i = 0; i < dp->alen; i++) { + if (dp->astr[i] != forbiddenword) + flags2[j++] = dp->astr[i]; + } + dp->alen--; + dp->astr = flags2; // XXX allowed forbidden words + } + } + dp = dp->next_homonym; + } + return 0; +} + +// add a custom dic. word to the hash table (public) +int HashMgr::add(const std::string& word) { + unsigned short* flags = NULL; + int al = 0; + if (remove_forbidden_flag(word)) { + int captype; + int wbl = word.size(); + int wcl = get_clen_and_captype(word, &captype); + add_word(word.c_str(), wbl, wcl, flags, al, NULL, false); + return add_hidden_capitalized_word(word, wcl, flags, al, NULL, + captype); + } + return 0; +} + +int HashMgr::add_with_affix(const char* word, const char* example) { + // detect captype and modify word length for UTF-8 encoding + struct hentry* dp = lookup(example); + remove_forbidden_flag(word); + if (dp && dp->astr) { + int captype; + int wbl = strlen(word); + int wcl = get_clen_and_captype(word, &captype); + if (aliasf) { + add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false); + } else { + unsigned short* flags = + (unsigned short*)malloc(dp->alen * sizeof(unsigned short)); + if (flags) { + memcpy((void*)flags, (void*)dp->astr, + dp->alen * sizeof(unsigned short)); + add_word(word, wbl, wcl, flags, dp->alen, NULL, false); + } else + return 1; + } + return add_hidden_capitalized_word(word, wcl, dp->astr, + dp->alen, NULL, captype); + } + return 1; +} + +// walk the hash table entry by entry - null at end +// initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp); +struct hentry* HashMgr::walk_hashtable(int& col, struct hentry* hp) const { + if (hp && hp->next != NULL) + return hp->next; + for (col++; col < tablesize; col++) { + if (tableptr[col]) + return tableptr[col]; + } + // null at end and reset to start + col = -1; + return NULL; +} + +// load a munched word list and build a hash table on the fly +int HashMgr::load_tables(const char* tpath, const char* key) { + int al; + char* ap; + char* dp; + char* dp2; + unsigned short* flags; + char* ts; + + // open dictionary file + FileMgr* dict = new FileMgr(tpath, key); + if (dict == NULL) + return 1; + + // first read the first line of file to get hash table size */ + if ((ts = dict->getline()) == NULL) { + HUNSPELL_WARNING(stderr, "error: empty dic file %s\n", tpath); + delete dict; + return 2; + } + mychomp(ts); + + /* remove byte order mark */ + if (strncmp(ts, "\xEF\xBB\xBF", 3) == 0) { + memmove(ts, ts + 3, strlen(ts + 3) + 1); + // warning: dic file begins with byte order mark: possible incompatibility + // with old Hunspell versions + } + + tablesize = atoi(ts); + + int nExtra = 5 + USERWORD; + + if (tablesize <= 0 || + (tablesize >= (std::numeric_limits<int>::max() - 1 - nExtra) / + int(sizeof(struct hentry*)))) { + HUNSPELL_WARNING( + stderr, "error: line 1: missing or bad word count in the dic file\n"); + delete dict; + return 4; + } + tablesize += nExtra; + if ((tablesize % 2) == 0) + tablesize++; + + // allocate the hash table + tableptr = (struct hentry**)calloc(tablesize, sizeof(struct hentry*)); + if (!tableptr) { + delete dict; + return 3; + } + + // loop through all words on much list and add to hash + // table and create word and affix strings + + while ((ts = dict->getline()) != NULL) { + mychomp(ts); + // split each line into word and morphological description + dp = ts; + while ((dp = strchr(dp, ':')) != NULL) { + if ((dp > ts + 3) && (*(dp - 3) == ' ' || *(dp - 3) == '\t')) { + for (dp -= 4; dp >= ts && (*dp == ' ' || *dp == '\t'); dp--) + ; + if (dp < ts) { // missing word + dp = NULL; + } else { + *(dp + 1) = '\0'; + dp = dp + 2; + } + break; + } + dp++; + } + + // tabulator is the old morphological field separator + dp2 = strchr(ts, '\t'); + if (dp2 && (!dp || dp2 < dp)) { + *dp2 = '\0'; + dp = dp2 + 1; + } + + // split each line into word and affix char strings + // "\/" signs slash in words (not affix separator) + // "/" at beginning of the line is word character (not affix separator) + ap = strchr(ts, '/'); + while (ap) { + if (ap == ts) { + ap++; + continue; + } else if (*(ap - 1) != '\\') + break; + // replace "\/" with "/" + for (char *sp = ap - 1; *sp; *sp = *(sp + 1), sp++) + ; + ap = strchr(ap, '/'); + } + + if (ap) { + *ap = '\0'; + if (aliasf) { + int index = atoi(ap + 1); + al = get_aliasf(index, &flags, dict); + if (!al) { + HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", + dict->getlinenum()); + *ap = '\0'; + } + } else { + al = decode_flags(&flags, ap + 1, dict); + if (al == -1) { + HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); + delete dict; + return 6; + } + std::sort(flags, flags + al); + } + } else { + al = 0; + ap = NULL; + flags = NULL; + } + + int captype; + int wbl = strlen(ts); + int wcl = get_clen_and_captype(ts, &captype); + // add the word and its index plus its capitalized form optionally + if (add_word(ts, wbl, wcl, flags, al, dp, false) || + add_hidden_capitalized_word(ts, wcl, flags, al, dp, captype)) { + delete dict; + return 5; + } + } + + delete dict; + return 0; +} + +// the hash function is a simple load and rotate +// algorithm borrowed +int HashMgr::hash(const char* word) const { + unsigned long hv = 0; + for (int i = 0; i < 4 && *word != 0; i++) + hv = (hv << 8) | (*word++); + while (*word != 0) { + ROTATE(hv, ROTATE_LEN); + hv ^= (*word++); + } + return (unsigned long)hv % tablesize; +} + +int HashMgr::decode_flags(unsigned short** result, char* flags, FileMgr* af) { + int len; + if (*flags == '\0') { + *result = NULL; + return 0; + } + switch (flag_mode) { + case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) + len = strlen(flags); + if (len % 2 == 1) + HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", + af->getlinenum()); + len /= 2; + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + for (int i = 0; i < len; i++) { + (*result)[i] = (((unsigned short)flags[i * 2]) << 8) + + (unsigned short)flags[i * 2 + 1]; + } + break; + } + case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 + // 23 233) + int i; + len = 1; + char* src = flags; + unsigned short* dest; + char* p; + for (p = flags; *p; p++) { + if (*p == ',') + len++; + } + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + dest = *result; + for (p = flags; *p; p++) { + if (*p == ',') { + i = atoi(src); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING( + stderr, "error: line %d: flag id %d is too large (max: %d)\n", + af->getlinenum(), i, DEFAULTFLAGS - 1); + *dest = (unsigned short)i; + if (*dest == 0) + HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", + af->getlinenum()); + src = p + 1; + dest++; + } + } + i = atoi(src); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING(stderr, + "error: line %d: flag id %d is too large (max: %d)\n", + af->getlinenum(), i, DEFAULTFLAGS - 1); + *dest = (unsigned short)i; + if (*dest == 0) + HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", + af->getlinenum()); + break; + } + case FLAG_UNI: { // UTF-8 characters + std::vector<w_char> w; + u8_u16(w, flags); + len = w.size(); + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + memcpy(*result, &w[0], len * sizeof(short)); + break; + } + default: { // Ispell's one-character flags (erfg -> e r f g) + unsigned short* dest; + len = strlen(flags); + *result = (unsigned short*)malloc(len * sizeof(unsigned short)); + if (!*result) + return -1; + dest = *result; + for (unsigned char* p = (unsigned char*)flags; *p; p++) { + *dest = (unsigned short)*p; + dest++; + } + } + } + return len; +} + +unsigned short HashMgr::decode_flag(const char* f) { + unsigned short s = 0; + int i; + switch (flag_mode) { + case FLAG_LONG: + s = ((unsigned short)f[0] << 8) + (unsigned short)f[1]; + break; + case FLAG_NUM: + i = atoi(f); + if (i >= DEFAULTFLAGS) + HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", + i, DEFAULTFLAGS - 1); + s = (unsigned short)i; + break; + case FLAG_UNI: { + std::vector<w_char> w; + u8_u16(w, f); + if (!w.empty()) + memcpy(&s, &w[0], 1 * sizeof(short)); + break; + } + default: + s = (unsigned short)*((unsigned char*)f); + } + if (s == 0) + HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); + return s; +} + +char* HashMgr::encode_flag(unsigned short f) { + if (f == 0) + return mystrdup("(NULL)"); + std::string ch; + if (flag_mode == FLAG_LONG) { + ch.push_back((unsigned char)(f >> 8)); + ch.push_back((unsigned char)(f - ((f >> 8) << 8))); + } else if (flag_mode == FLAG_NUM) { + std::ostringstream stream; + stream << f; + ch = stream.str(); + } else if (flag_mode == FLAG_UNI) { + const w_char* w_c = (const w_char*)&f; + std::vector<w_char> w(w_c, w_c + 1); + u16_u8(ch, w); + } else { + ch.push_back((unsigned char)(f)); + } + return mystrdup(ch.c_str()); +} + +// read in aff file and set flag mode +int HashMgr::load_config(const char* affpath, const char* key) { + char* line; // io buffers + int firstline = 1; + + // open the affix file + FileMgr* afflst = new FileMgr(affpath, key); + if (!afflst) { + HUNSPELL_WARNING( + stderr, "Error - could not open affix description file %s\n", affpath); + return 1; + } + + // read in each line ignoring any that do not + // start with a known line type indicator + + while ((line = afflst->getline()) != NULL) { + mychomp(line); + + /* remove byte order mark */ + if (firstline) { + firstline = 0; + if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) + memmove(line, line + 3, strlen(line + 3) + 1); + } + + /* parse in the try string */ + if ((strncmp(line, "FLAG", 4) == 0) && isspace(line[4])) { + if (flag_mode != FLAG_CHAR) { + HUNSPELL_WARNING(stderr, + "error: line %d: multiple definitions of the FLAG " + "affix file parameter\n", + afflst->getlinenum()); + } + if (strstr(line, "long")) + flag_mode = FLAG_LONG; + if (strstr(line, "num")) + flag_mode = FLAG_NUM; + if (strstr(line, "UTF-8")) + flag_mode = FLAG_UNI; + if (flag_mode == FLAG_CHAR) { + HUNSPELL_WARNING( + stderr, + "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", + afflst->getlinenum()); + } + } + if (strncmp(line, "FORBIDDENWORD", 13) == 0) { + char* st = NULL; + if (parse_string(line, &st, afflst->getlinenum())) { + delete afflst; + return 1; + } + forbiddenword = decode_flag(st); + free(st); + } + if (strncmp(line, "SET", 3) == 0) { + if (parse_string(line, &enc, afflst->getlinenum())) { + delete afflst; + return 1; + } + if (strcmp(enc, "UTF-8") == 0) { + utf8 = 1; +#ifndef OPENOFFICEORG +#ifndef MOZILLA_CLIENT + initialize_utf_tbl(); +#endif +#endif + } else + csconv = get_current_cs(enc); + } + if (strncmp(line, "LANG", 4) == 0) { + if (parse_string(line, &lang, afflst->getlinenum())) { + delete afflst; + return 1; + } + langnum = get_lang_num(lang); + } + + /* parse in the ignored characters (for example, Arabic optional diacritics + * characters */ + if (strncmp(line, "IGNORE", 6) == 0) { + if (!parse_array(line, &ignorechars, ignorechars_utf16, + utf8, afflst->getlinenum())) { + delete afflst; + return 1; + } + } + + if ((strncmp(line, "AF", 2) == 0) && isspace(line[2])) { + if (parse_aliasf(line, afflst)) { + delete afflst; + return 1; + } + } + + if ((strncmp(line, "AM", 2) == 0) && isspace(line[2])) { + if (parse_aliasm(line, afflst)) { + delete afflst; + return 1; + } + } + + if (strncmp(line, "COMPLEXPREFIXES", 15) == 0) + complexprefixes = 1; + if (((strncmp(line, "SFX", 3) == 0) || (strncmp(line, "PFX", 3) == 0)) && + isspace(line[3])) + break; + } + if (csconv == NULL) + csconv = get_current_cs(SPELL_ENCODING); + delete afflst; + return 0; +} + +/* parse in the ALIAS table */ +int HashMgr::parse_aliasf(char* line, FileMgr* af) { + if (numaliasf != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numaliasf = atoi(piece); + if (numaliasf < 1) { + numaliasf = 0; + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + aliasf = + (unsigned short**)malloc(numaliasf * sizeof(unsigned short*)); + aliasflen = + (unsigned short*)malloc(numaliasf * sizeof(unsigned short)); + if (!aliasf || !aliasflen) { + numaliasf = 0; + if (aliasf) + free(aliasf); + if (aliasflen) + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + numaliasf = 0; + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numaliasf lines to read in the remainder of the table */ + char* nl; + for (int j = 0; j < numaliasf; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + aliasf[j] = NULL; + aliasflen[j] = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "AF", 2) != 0) { + numaliasf = 0; + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + break; + } + case 1: { + aliasflen[j] = + (unsigned short)decode_flags(&(aliasf[j]), piece, af); + std::sort(aliasf[j], aliasf[j] + aliasflen[j]); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (!aliasf[j]) { + free(aliasf); + free(aliasflen); + aliasf = NULL; + aliasflen = NULL; + numaliasf = 0; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + } + return 0; +} + +int HashMgr::is_aliasf() { + return (aliasf != NULL); +} + +int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) { + if ((index > 0) && (index <= numaliasf)) { + *fvec = aliasf[index - 1]; + return aliasflen[index - 1]; + } + HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", + af->getlinenum(), index); + *fvec = NULL; + return 0; +} + +/* parse morph alias definitions */ +int HashMgr::parse_aliasm(char* line, FileMgr* af) { + if (numaliasm != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return 1; + } + char* tp = line; + char* piece; + int i = 0; + int np = 0; + piece = mystrsep(&tp, 0); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + np++; + break; + } + case 1: { + numaliasm = atoi(piece); + if (numaliasm < 1) { + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return 1; + } + aliasm = (char**)malloc(numaliasm * sizeof(char*)); + if (!aliasm) { + numaliasm = 0; + return 1; + } + np++; + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, 0); + } + if (np != 2) { + numaliasm = 0; + free(aliasm); + aliasm = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", + af->getlinenum()); + return 1; + } + + /* now parse the numaliasm lines to read in the remainder of the table */ + char* nl = line; + for (int j = 0; j < numaliasm; j++) { + if ((nl = af->getline()) == NULL) + return 1; + mychomp(nl); + tp = nl; + i = 0; + aliasm[j] = NULL; + piece = mystrsep(&tp, ' '); + while (piece) { + if (*piece != '\0') { + switch (i) { + case 0: { + if (strncmp(piece, "AM", 2) != 0) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + numaliasm = 0; + free(aliasm); + aliasm = NULL; + return 1; + } + break; + } + case 1: { + // add the remaining of the line + if (*tp) { + *(tp - 1) = ' '; + tp = tp + strlen(tp); + } + std::string chunk(piece); + if (complexprefixes) { + if (utf8) + reverseword_utf(chunk); + else + reverseword(chunk); + } + aliasm[j] = mystrdup(chunk.c_str()); + break; + } + default: + break; + } + i++; + } + piece = mystrsep(&tp, ' '); + } + if (!aliasm[j]) { + numaliasm = 0; + free(aliasm); + aliasm = NULL; + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return 1; + } + } + return 0; +} + +int HashMgr::is_aliasm() { + return (aliasm != NULL); +} + +char* HashMgr::get_aliasm(int index) { + if ((index > 0) && (index <= numaliasm)) + return aliasm[index - 1]; + HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); + return NULL; +} diff --git a/extensions/spellcheck/hunspell/src/hashmgr.hxx b/extensions/spellcheck/hunspell/src/hashmgr.hxx new file mode 100644 index 000000000..95b06b13f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hashmgr.hxx @@ -0,0 +1,149 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _HASHMGR_HXX_ +#define _HASHMGR_HXX_ + +#include "hunvisapi.h" + +#include <stdio.h> +#include <string> +#include <vector> + +#include "htypes.hxx" +#include "filemgr.hxx" +#include "w_char.hxx" + +enum flag { FLAG_CHAR, FLAG_LONG, FLAG_NUM, FLAG_UNI }; + +class LIBHUNSPELL_DLL_EXPORTED HashMgr { + int tablesize; + struct hentry** tableptr; + flag flag_mode; + int complexprefixes; + int utf8; + unsigned short forbiddenword; + int langnum; + char* enc; + char* lang; + struct cs_info* csconv; + char* ignorechars; + std::vector<w_char> ignorechars_utf16; + int numaliasf; // flag vector `compression' with aliases + unsigned short** aliasf; + unsigned short* aliasflen; + int numaliasm; // morphological desciption `compression' with aliases + char** aliasm; + + public: + HashMgr(const char* tpath, const char* apath, const char* key = NULL); + ~HashMgr(); + + struct hentry* lookup(const char*) const; + int hash(const char*) const; + struct hentry* walk_hashtable(int& col, struct hentry* hp) const; + + int add(const std::string& word); + int add_with_affix(const char* word, const char* pattern); + int remove(const char* word); + int decode_flags(unsigned short** result, char* flags, FileMgr* af); + unsigned short decode_flag(const char* flag); + char* encode_flag(unsigned short flag); + int is_aliasf(); + int get_aliasf(int index, unsigned short** fvec, FileMgr* af); + int is_aliasm(); + char* get_aliasm(int index); + + private: + int get_clen_and_captype(const std::string& word, int* captype); + int load_tables(const char* tpath, const char* key); + int add_word(const char* word, + int wbl, + int wcl, + unsigned short* ap, + int al, + const char* desc, + bool onlyupcase); + int load_config(const char* affpath, const char* key); + int parse_aliasf(char* line, FileMgr* af); + int add_hidden_capitalized_word(const std::string& word, + int wcl, + unsigned short* flags, + int al, + char* dp, + int captype); + int parse_aliasm(char* line, FileMgr* af); + int remove_forbidden_flag(const std::string& word); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/htypes.hxx b/extensions/spellcheck/hunspell/src/htypes.hxx new file mode 100644 index 000000000..d24439441 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/htypes.hxx @@ -0,0 +1,71 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _HTYPES_HXX_ +#define _HTYPES_HXX_ + +#define ROTATE_LEN 5 + +#define ROTATE(v, q) \ + (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1)); + +// hentry options +#define H_OPT (1 << 0) +#define H_OPT_ALIASM (1 << 1) +#define H_OPT_PHON (1 << 2) + +// see also csutil.hxx +#define HENTRY_WORD(h) &(h->word[0]) + +// approx. number of user defined words +#define USERWORD 1000 + +struct hentry { + unsigned char blen; // word length in bytes + unsigned char clen; // word length in characters (different for UTF-8 enc.) + short alen; // length of affix flag vector + unsigned short* astr; // affix flag vector + struct hentry* next; // next word with same hash code + struct hentry* next_homonym; // next homonym word (with same hash code) + char var; // variable fields (only for special pronounciation yet) + char word[1]; // variable-length word (8-bit or UTF-8 encoding) +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunspell.cxx b/extensions/spellcheck/hunspell/src/hunspell.cxx new file mode 100644 index 000000000..7ff1e2bcf --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.cxx @@ -0,0 +1,1895 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "hunspell.hxx" +#include "hunspell.h" +#ifndef MOZILLA_CLIENT +#include "config.h" +#endif +#include "csutil.hxx" + +#include <limits> +#include <string> + +#define MAXWORDLEN 100 +#define MAXWORDUTF8LEN (MAXWORDLEN * 3) + +Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) { + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + affixpath = mystrdup(affpath); + maxdic = 0; + + /* first set up the hash manager */ + pHMgr[0] = new HashMgr(dpath, affpath, key); + if (pHMgr[0]) + maxdic = 1; + + /* next set up the affix manager */ + /* it needs access to the hash manager lookup methods */ + pAMgr = new AffixMgr(affpath, pHMgr, &maxdic, key); + + /* get the preferred try string and the dictionary */ + /* encoding from the Affix Manager for that dictionary */ + char* try_string = pAMgr->get_try_string(); + encoding = pAMgr->get_encoding(); + langnum = pAMgr->get_langnum(); + utf8 = pAMgr->get_utf8(); + if (!utf8) + csconv = get_current_cs(encoding); + complexprefixes = pAMgr->get_complexprefixes(); + wordbreak = pAMgr->get_breaktable(); + + /* and finally set up the suggestion manager */ + pSMgr = new SuggestMgr(try_string, MAXSUGGESTION, pAMgr); + if (try_string) + free(try_string); +} + +Hunspell::~Hunspell() { + delete pSMgr; + delete pAMgr; + for (int i = 0; i < maxdic; i++) + delete pHMgr[i]; + maxdic = 0; + pSMgr = NULL; + pAMgr = NULL; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif + csconv = NULL; + if (encoding) + free(encoding); + encoding = NULL; + if (affixpath) + free(affixpath); + affixpath = NULL; +} + +// load extra dictionaries +int Hunspell::add_dic(const char* dpath, const char* key) { + if (maxdic == MAXDIC || !affixpath) + return 1; + pHMgr[maxdic] = new HashMgr(dpath, affixpath, key); + if (pHMgr[maxdic]) + maxdic++; + else + return 1; + return 0; +} + +// make a copy of src at destination while removing all leading +// blanks and removing any trailing periods after recording +// their presence with the abbreviation flag +// also since already going through character by character, +// set the capitalization type +// return the length of the "cleaned" (and UTF-8 encoded) word + +size_t Hunspell::cleanword2(std::string& dest, + std::vector<w_char>& dest_utf, + const char* src, + int* nc, + int* pcaptype, + size_t* pabbrev) { + dest.clear(); + dest_utf.clear(); + + const char* q = src; + + // first skip over any leading blanks + while ((*q != '\0') && (*q == ' ')) + q++; + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + int nl = strlen(q); + while ((nl > 0) && (*(q + nl - 1) == '.')) { + nl--; + (*pabbrev)++; + } + + // if no characters are left it can't be capitalized + if (nl <= 0) { + *pcaptype = NOCAP; + return 0; + } + + dest.append(q, nl); + nl = dest.size(); + if (utf8) { + *nc = u8_u16(dest_utf, dest); + *pcaptype = get_captype_utf8(dest_utf, langnum); + } else { + *pcaptype = get_captype(dest, csconv); + *nc = nl; + } + return nl; +} + +void Hunspell::cleanword(std::string& dest, + const char* src, + int* pcaptype, + int* pabbrev) { + dest.clear(); + const unsigned char* q = (const unsigned char*)src; + int firstcap = 0; + + // first skip over any leading blanks + while ((*q != '\0') && (*q == ' ')) + q++; + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + int nl = strlen((const char*)q); + while ((nl > 0) && (*(q + nl - 1) == '.')) { + nl--; + (*pabbrev)++; + } + + // if no characters are left it can't be capitalized + if (nl <= 0) { + *pcaptype = NOCAP; + return; + } + + // now determine the capitalization type of the first nl letters + int ncap = 0; + int nneutral = 0; + int nc = 0; + + if (!utf8) { + while (nl > 0) { + nc++; + if (csconv[(*q)].ccase) + ncap++; + if (csconv[(*q)].cupper == csconv[(*q)].clower) + nneutral++; + dest.push_back(*q++); + nl--; + } + // remember to terminate the destination string + firstcap = csconv[static_cast<unsigned char>(dest[0])].ccase; + } else { + std::vector<w_char> t; + u8_u16(t, src); + for (size_t i = 0; i < t.size(); ++i) { + unsigned short idx = (t[i].h << 8) + t[i].l; + unsigned short low = unicodetolower(idx, langnum); + if (idx != low) + ncap++; + if (unicodetoupper(idx, langnum) == low) + nneutral++; + } + u16_u8(dest, t); + if (ncap) { + unsigned short idx = (t[0].h << 8) + t[0].l; + firstcap = (idx != unicodetolower(idx, langnum)); + } + } + + // now finally set the captype + if (ncap == 0) { + *pcaptype = NOCAP; + } else if ((ncap == 1) && firstcap) { + *pcaptype = INITCAP; + } else if ((ncap == nc) || ((ncap + nneutral) == nc)) { + *pcaptype = ALLCAP; + } else if ((ncap > 1) && firstcap) { + *pcaptype = HUHINITCAP; + } else { + *pcaptype = HUHCAP; + } +} + +void Hunspell::mkallcap(std::string& u8) { + if (utf8) { + std::vector<w_char> u16; + u8_u16(u16, u8); + ::mkallcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkallcap(u8, csconv); + } +} + +int Hunspell::mkallsmall2(std::string& u8, std::vector<w_char>& u16) { + if (utf8) { + ::mkallsmall_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkallsmall(u8, csconv); + } + return u8.size(); +} + +// convert UTF-8 sharp S codes to latin 1 +std::string Hunspell::sharps_u8_l1(const std::string& source) { + std::string dest(source); + mystrrep(dest, "\xC3\x9F", "\xDF"); + return dest; +} + +// recursive search for right ss - sharp s permutations +hentry* Hunspell::spellsharps(std::string& base, + size_t n_pos, + int n, + int repnum, + int* info, + char** root) { + size_t pos = base.find("ss", n_pos); + if (pos != std::string::npos && (n < MAXSHARPS)) { + base[pos] = '\xC3'; + base[pos + 1] = '\x9F'; + hentry* h = spellsharps(base, pos + 2, n + 1, repnum + 1, info, root); + if (h) + return h; + base[pos] = 's'; + base[pos + 1] = 's'; + h = spellsharps(base, pos + 2, n + 1, repnum, info, root); + if (h) + return h; + } else if (repnum > 0) { + if (utf8) + return checkword(base.c_str(), info, root); + std::string tmp(sharps_u8_l1(base)); + return checkword(tmp.c_str(), info, root); + } + return NULL; +} + +int Hunspell::is_keepcase(const hentry* rv) { + return pAMgr && rv->astr && pAMgr->get_keepcase() && + TESTAFF(rv->astr, pAMgr->get_keepcase(), rv->alen); +} + +/* insert a word to the beginning of the suggestion array and return ns */ +int Hunspell::insert_sug(char*** slst, const char* word, int ns) { + if (!*slst) + return ns; + char* dup = mystrdup(word); + if (!dup) + return ns; + if (ns == MAXSUGGESTION) { + ns--; + free((*slst)[ns]); + } + for (int k = ns; k > 0; k--) + (*slst)[k] = (*slst)[k - 1]; + (*slst)[0] = dup; + return ns + 1; +} + +int Hunspell::spell(const char* word, int* info, char** root) { + struct hentry* rv = NULL; + + int info2 = 0; + if (!info) + info = &info2; + else + *info = 0; + + // Hunspell supports XML input of the simplified API (see manual) + if (strcmp(word, SPELL_XML) == 0) + return 1; + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector<w_char> sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + } + +#ifdef MOZILLA_CLIENT + // accept the abbreviated words without dots + // workaround for the incomplete tokenization of Mozilla + abbv = 1; +#endif + + if (wl == 0 || maxdic == 0) + return 1; + if (root) + *root = NULL; + + // allow numbers with dots, dashes and commas (but forbid double separators: + // "..", "--" etc.) + enum { NBEGIN, NNUM, NSEP }; + int nstate = NBEGIN; + size_t i; + + for (i = 0; (i < wl); i++) { + if ((scw[i] <= '9') && (scw[i] >= '0')) { + nstate = NNUM; + } else if ((scw[i] == ',') || (scw[i] == '.') || (scw[i] == '-')) { + if ((nstate == NSEP) || (i == 0)) + break; + nstate = NSEP; + } else + break; + } + if ((i == wl) && (nstate == NNUM)) + return 1; + + switch (captype) { + case HUHCAP: + /* FALLTHROUGH */ + case HUHINITCAP: + *info += SPELL_ORIGCAP; + /* FALLTHROUGH */ + case NOCAP: + rv = checkword(scw.c_str(), info, root); + if ((abbv) && !(rv)) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + } + break; + case ALLCAP: { + *info += SPELL_ORIGCAP; + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + if (rv) + break; + } + // Spec. prefix handling for Catalan, French, Italian: + // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia). + size_t apos = pAMgr ? scw.find('\'') : std::string::npos; + if (apos != std::string::npos) { + mkallsmall2(scw, sunicw); + //conversion may result in string with different len to pre-mkallsmall2 + //so re-scan + if (apos != std::string::npos && apos < scw.size() - 1) { + std::string part1 = scw.substr(0, apos+1); + std::string part2 = scw.substr(apos+1); + if (utf8) { + std::vector<w_char> part1u, part2u; + u8_u16(part1u, part1); + u8_u16(part2u, part2); + mkinitcap2(part2, part2u); + scw = part1 + part2; + sunicw = part1u; + sunicw.insert(sunicw.end(), part2u.begin(), part2u.end()); + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } else { + mkinitcap2(part2, sunicw); + scw = part1 + part2; + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } + mkinitcap2(scw, sunicw); + rv = checkword(scw.c_str(), info, root); + if (rv) + break; + } + } + if (pAMgr && pAMgr->get_checksharps() && scw.find("SS") != std::string::npos) { + + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + if (!rv) { + mkinitcap2(scw, sunicw); + rv = spellsharps(scw, 0, 0, 0, info, root); + } + if ((abbv) && !(rv)) { + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + if (!rv) { + u8buffer = std::string(scw); + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root); + } + } + if (rv) + break; + } + } + case INITCAP: { + + *info += SPELL_ORIGCAP; + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + if (captype == INITCAP) + *info += SPELL_INITCAP; + rv = checkword(scw.c_str(), info, root); + if (captype == INITCAP) + *info -= SPELL_INITCAP; + // forbid bad capitalization + // (for example, ijs -> Ijs instead of IJs in Dutch) + // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag) + if (*info & SPELL_FORBIDDEN) { + rv = NULL; + break; + } + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = NULL; + if (rv) + break; + + rv = checkword(u8buffer.c_str(), info, root); + if (abbv && !rv) { + u8buffer.push_back('.'); + rv = checkword(u8buffer.c_str(), info, root); + if (!rv) { + u8buffer = scw; + u8buffer.push_back('.'); + if (captype == INITCAP) + *info += SPELL_INITCAP; + rv = checkword(u8buffer.c_str(), info, root); + if (captype == INITCAP) + *info -= SPELL_INITCAP; + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = NULL; + break; + } + } + if (rv && is_keepcase(rv) && + ((captype == ALLCAP) || + // if CHECKSHARPS: KEEPCASE words with \xDF are allowed + // in INITCAP form, too. + !(pAMgr->get_checksharps() && + ((utf8 && u8buffer.find("\xC3\x9F") != std::string::npos) || + (!utf8 && u8buffer.find('\xDF') != std::string::npos))))) + rv = NULL; + break; + } + } + + if (rv) { + if (pAMgr && pAMgr->get_warn() && rv->astr && + TESTAFF(rv->astr, pAMgr->get_warn(), rv->alen)) { + *info += SPELL_WARN; + if (pAMgr->get_forbidwarn()) + return 0; + return HUNSPELL_OK_WARN; + } + return HUNSPELL_OK; + } + + // recursive breaking at break points + if (wordbreak) { + + int nbr = 0; + wl = scw.size(); + int numbreak = pAMgr ? pAMgr->get_numbreak() : 0; + + // calculate break points for recursion limit + for (int j = 0; j < numbreak; j++) { + size_t len = strlen(wordbreak[j]); + size_t pos = 0; + while ((pos = scw.find(wordbreak[j], pos, len)) != std::string::npos) { + ++nbr; + pos += len; + } + } + if (nbr >= 10) + return 0; + + // check boundary patterns (^begin and end$) + for (int j = 0; j < numbreak; j++) { + size_t plen = strlen(wordbreak[j]); + if (plen == 1 || plen > wl) + continue; + + if (wordbreak[j][0] == '^' && + scw.compare(0, plen - 1, wordbreak[j] + 1, plen -1) == 0 && spell(scw.c_str() + plen - 1)) + return 1; + + if (wordbreak[j][plen - 1] == '$' && + scw.compare(wl - plen + 1, plen - 1, wordbreak[j], plen - 1) == 0) { + char r = scw[wl - plen + 1]; + scw[wl - plen + 1] = '\0'; + if (spell(scw.c_str())) + return 1; + scw[wl - plen + 1] = r; + } + } + + // other patterns + for (int j = 0; j < numbreak; j++) { + size_t plen = strlen(wordbreak[j]); + size_t found = scw.find(wordbreak[j]); + if ((found > 0) && (found < wl - plen)) { + if (!spell(scw.c_str() + found + plen)) + continue; + char r = scw[found]; + scw[found] = '\0'; + // examine 2 sides of the break point + if (spell(scw.c_str())) + return 1; + scw[found] = r; + + // LANG_hu: spec. dash rule + if (langnum == LANG_hu && strcmp(wordbreak[j], "-") == 0) { + r = scw[found + 1]; + scw[found + 1] = '\0'; + if (spell(scw.c_str())) + return 1; // check the first part with dash + scw[found + 1] = r; + } + // end of LANG specific region + } + } + } + + return 0; +} + +struct hentry* Hunspell::checkword(const char* w, int* info, char** root) { + struct hentry* he = NULL; + bool usebuffer = false; + int len, i; + std::string w2; + const char* word; + + char* ignoredchars = pAMgr ? pAMgr->get_ignore() : NULL; + if (ignoredchars != NULL) { + w2.assign(w); + if (utf8) { + const std::vector<w_char>& ignoredchars_utf16 = + pAMgr->get_ignore_utf16(); + remove_ignored_chars_utf(w2, ignoredchars_utf16); + } else { + remove_ignored_chars(w2, ignoredchars); + } + word = w2.c_str(); + usebuffer = true; + } else + word = w; + + len = strlen(word); + + if (!len) + return NULL; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + if (!usebuffer) { + w2.assign(word); + usebuffer = true; + } + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + } + + if (usebuffer) { + word = w2.c_str(); + } + + // look word in hash table + for (i = 0; (i < maxdic) && !he; i++) { + he = (pHMgr[i])->lookup(word); + + // check forbidden and onlyincompound words + if ((he) && (he->astr) && (pAMgr) && + TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { + if (info) + *info += SPELL_FORBIDDEN; + // LANG_hu section: set dash information for suggestions + if (langnum == LANG_hu) { + if (pAMgr->get_compoundflag() && + TESTAFF(he->astr, pAMgr->get_compoundflag(), he->alen)) { + if (info) + *info += SPELL_COMPOUND; + } + } + return NULL; + } + + // he = next not needaffix, onlyincompound homonym or onlyupcase word + while (he && (he->astr) && pAMgr && + ((pAMgr->get_needaffix() && + TESTAFF(he->astr, pAMgr->get_needaffix(), he->alen)) || + (pAMgr->get_onlyincompound() && + TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || + (info && (*info & SPELL_INITCAP) && + TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) + he = he->next_homonym; + } + + // check with affixes + if (!he && pAMgr) { + // try stripping off affixes */ + he = pAMgr->affix_check(word, len, 0); + + // check compound restriction and onlyupcase + if (he && he->astr && + ((pAMgr->get_onlyincompound() && + TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) || + (info && (*info & SPELL_INITCAP) && + TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) { + he = NULL; + } + + if (he) { + if ((he->astr) && (pAMgr) && + TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { + if (info) + *info += SPELL_FORBIDDEN; + return NULL; + } + if (root) { + std::string word_root(he->word); + if (complexprefixes) { + if (utf8) + reverseword_utf(word_root); + else + reverseword(word_root); + } + *root = mystrdup(word_root.c_str()); + } + // try check compound word + } else if (pAMgr->get_compound()) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + he = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 0, info); + // LANG_hu section: `moving rule' with last dash + if ((!he) && (langnum == LANG_hu) && (word[len - 1] == '-')) { + char* dup = mystrdup(word); + if (!dup) + return NULL; + dup[len - 1] = '\0'; + he = pAMgr->compound_check(dup, len - 1, -5, 0, 100, 0, NULL, (hentry**)&rwords, 1, 0, + info); + free(dup); + } + // end of LANG specific region + if (he) { + if (root) { + std::string word_root(he->word); + if (complexprefixes) { + if (utf8) + reverseword_utf(word_root); + else + reverseword(word_root); + } + *root = mystrdup(word_root.c_str()); + } + if (info) + *info += SPELL_COMPOUND; + } + } + } + + return he; +} + +int Hunspell::suggest(char*** slst, const char* word) { + int onlycmpdsug = 0; + if (!pSMgr || maxdic == 0) + return 0; + *slst = NULL; + // process XML input of the simplified API (see manual) + if (strncmp(word, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) { + return spellml(slst, word); + } + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector<w_char> sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + + if (wl == 0) + return 0; + } + + int ns = 0; + int capwords = 0; + + // check capitalized form for FORCEUCASE + if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) { + int info = SPELL_ORIGCAP; + if (checkword(scw.c_str(), &info, NULL)) { + std::string form(scw); + mkinitcap(form); + + char** wlst = (char**)malloc(MAXSUGGESTION * sizeof(char*)); + if (wlst == NULL) + return -1; + *slst = wlst; + wlst[0] = mystrdup(form.c_str()); + for (int i = 1; i < MAXSUGGESTION; ++i) { + wlst[i] = NULL; + } + + return 1; + } + } + + switch (captype) { + case NOCAP: { + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + break; + } + + case INITCAP: { + capwords = 1; + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + if (ns == -1) + break; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + break; + } + case HUHINITCAP: + capwords = 1; + case HUHCAP: { + ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug); + if (ns != -1) { + // something.The -> something. The + size_t dot_pos = scw.find('.'); + if (dot_pos != std::string::npos) { + std::string postdot = scw.substr(dot_pos + 1); + int captype_; + if (utf8) { + std::vector<w_char> postdotu; + u8_u16(postdotu, postdot); + captype_ = get_captype_utf8(postdotu, langnum); + } else { + captype_ = get_captype(postdot, csconv); + } + if (captype_ == INITCAP) { + std::string str(scw); + str.insert(dot_pos + 1, 1, ' '); + ns = insert_sug(slst, str.c_str(), ns); + } + } + + std::string wspace; + + if (captype == HUHINITCAP) { + // TheOpenOffice.org -> The OpenOffice.org + wspace = scw; + mkinitsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + } + wspace = scw; + mkallsmall2(wspace, sunicw); + if (spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + int prevns = ns; + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + if (captype == HUHINITCAP) { + mkinitcap2(wspace, sunicw); + if (spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + } + // aNew -> "a New" (instead of "a new") + for (int j = prevns; j < ns; j++) { + char* space = strchr((*slst)[j], ' '); + if (space) { + size_t slen = strlen(space + 1); + // different case after space (need capitalisation) + if ((slen < wl) && strcmp(scw.c_str() + wl - slen, space + 1)) { + std::string first((*slst)[j], space + 1); + std::string second(space + 1); + std::vector<w_char> w; + if (utf8) + u8_u16(w, second); + mkinitcap2(second, w); + // set as first suggestion + char* r = (*slst)[j]; + for (int k = j; k > 0; k--) + (*slst)[k] = (*slst)[k - 1]; + free(r); + (*slst)[0] = mystrdup((first + second).c_str()); + } + } + } + } + break; + } + + case ALLCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + if (ns == -1) + break; + if (pAMgr && pAMgr->get_keepcase() && spell(wspace.c_str())) + ns = insert_sug(slst, wspace.c_str(), ns); + mkinitcap2(wspace, sunicw); + ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug); + for (int j = 0; j < ns; j++) { + std::string form((*slst)[j]); + mkallcap(form); + + if (pAMgr && pAMgr->get_checksharps()) { + if (utf8) { + mystrrep(form, "\xC3\x9F", "SS"); + } else { + mystrrep(form, "\xDF", "SS"); + } + } + + free((*slst)[j]); + (*slst)[j] = mystrdup(form.c_str()); + + } + break; + } + } + + // LANG_hu section: replace '-' with ' ' in Hungarian + if (langnum == LANG_hu) { + for (int j = 0; j < ns; j++) { + char* pos = strchr((*slst)[j], '-'); + if (pos) { + int info; + *pos = '\0'; + std::string w((*slst)[j]); + w.append(pos + 1); + (void)spell(w.c_str(), &info, NULL); + if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) { + *pos = ' '; + } else + *pos = '-'; + } + } + } + // END OF LANG_hu section + + // try ngram approach since found nothing or only compound words + if (pAMgr && (ns == 0 || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0) && + (*slst)) { + switch (captype) { + case NOCAP: { + ns = pSMgr->ngsuggest(*slst, scw.c_str(), ns, pHMgr, maxdic); + break; + } + case HUHINITCAP: + capwords = 1; + case HUHCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + break; + } + case INITCAP: { + capwords = 1; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + break; + } + case ALLCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + int oldns = ns; + ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic); + for (int j = oldns; j < ns; j++) { + std::string form((*slst)[j]); + mkallcap(form); + free((*slst)[j]); + (*slst)[j] = mystrdup(form.c_str()); + } + break; + } + } + } + + // try dash suggestion (Afo-American -> Afro-American) + size_t dash_pos = scw.find('-'); + if (dash_pos != std::string::npos) { + int nodashsug = 1; + for (int j = 0; j < ns && nodashsug == 1; j++) { + if (strchr((*slst)[j], '-')) + nodashsug = 0; + } + + size_t prev_pos = 0; + bool last = false; + + while (nodashsug && !last) { + if (dash_pos == scw.size()) + last = 1; + std::string chunk = scw.substr(prev_pos, dash_pos - prev_pos); + if (!spell(chunk.c_str())) { + char** nlst = NULL; + int nn = suggest(&nlst, chunk.c_str()); + for (int j = nn - 1; j >= 0; j--) { + std::string wspace = scw.substr(0, prev_pos); + wspace.append(nlst[j]); + if (!last) { + wspace.append("-"); + wspace.append(scw.substr(dash_pos + 1)); + } + ns = insert_sug(slst, wspace.c_str(), ns); + free(nlst[j]); + } + if (nlst != NULL) + free(nlst); + nodashsug = 0; + } + if (!last) { + prev_pos = dash_pos + 1; + dash_pos = scw.find('-', prev_pos); + } + if (dash_pos == std::string::npos) + dash_pos = scw.size(); + } + } + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + for (int j = 0; j < ns; j++) { + std::string root((*slst)[j]); + free((*slst)[j]); + if (utf8) + reverseword_utf(root); + else + reverseword(root); + (*slst)[j] = mystrdup(root.c_str()); + } + } + + // capitalize + if (capwords) + for (int j = 0; j < ns; j++) { + std::string form((*slst)[j]); + free((*slst)[j]); + mkinitcap(form); + (*slst)[j] = mystrdup(form.c_str()); + } + + // expand suggestions with dot(s) + if (abbv && pAMgr && pAMgr->get_sugswithdots()) { + for (int j = 0; j < ns; j++) { + (*slst)[j] = (char*)realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv); + strcat((*slst)[j], word + strlen(word) - abbv); + } + } + + // remove bad capitalized and forbidden forms + if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) { + switch (captype) { + case INITCAP: + case ALLCAP: { + int l = 0; + for (int j = 0; j < ns; j++) { + if (!strchr((*slst)[j], ' ') && !spell((*slst)[j])) { + std::string s; + std::vector<w_char> w; + if (utf8) { + u8_u16(w, (*slst)[j]); + } else { + s = (*slst)[j]; + } + mkallsmall2(s, w); + free((*slst)[j]); + if (spell(s.c_str())) { + (*slst)[l] = mystrdup(s.c_str()); + if ((*slst)[l]) + l++; + } else { + mkinitcap2(s, w); + if (spell(s.c_str())) { + (*slst)[l] = mystrdup(s.c_str()); + if ((*slst)[l]) + l++; + } + } + } else { + (*slst)[l] = (*slst)[j]; + l++; + } + } + ns = l; + } + } + } + + // remove duplications + int l = 0; + for (int j = 0; j < ns; j++) { + (*slst)[l] = (*slst)[j]; + for (int k = 0; k < l; k++) { + if (strcmp((*slst)[k], (*slst)[j]) == 0) { + free((*slst)[j]); + l--; + break; + } + } + l++; + } + ns = l; + + // output conversion + rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL; + for (int j = 0; rl && j < ns; j++) { + std::string wspace; + if (rl->conv((*slst)[j], wspace) > 0) { + free((*slst)[j]); + (*slst)[j] = mystrdup(wspace.c_str()); + } + } + + // if suggestions removed by nosuggest, onlyincompound parameters + if (l == 0 && *slst) { + free(*slst); + *slst = NULL; + } + return l; +} + +void Hunspell::free_list(char*** slst, int n) { + freelist(slst, n); +} + +char* Hunspell::get_dic_encoding() { + return encoding; +} + +int Hunspell::stem(char*** slst, char** desc, int n) { + + std::string result2; + *slst = NULL; + if (n == 0) + return 0; + for (int i = 0; i < n; i++) { + + std::string result; + + // add compound word parts (except the last one) + char* s = (char*)desc[i]; + char* part = strstr(s, MORPH_PART); + if (part) { + char* nextpart = strstr(part + 1, MORPH_PART); + while (nextpart) { + std::string field; + copy_field(field, part, MORPH_PART); + result.append(field); + part = nextpart; + nextpart = strstr(part + 1, MORPH_PART); + } + s = part; + } + + char** pl; + std::string tok(s); + size_t alt = 0; + while ((alt = tok.find(" | ", alt)) != std::string::npos) { + tok[alt + 1] = MSEP_ALT; + } + int pln = line_tok(tok.c_str(), &pl, MSEP_ALT); + for (int k = 0; k < pln; k++) { + // add derivational suffixes + if (strstr(pl[k], MORPH_DERI_SFX)) { + // remove inflectional suffixes + char* is = strstr(pl[k], MORPH_INFL_SFX); + if (is) + *is = '\0'; + char* sg = pSMgr->suggest_gen(&(pl[k]), 1, pl[k]); + if (sg) { + char** gen; + int genl = line_tok(sg, &gen, MSEP_REC); + free(sg); + for (int j = 0; j < genl; j++) { + result2.push_back(MSEP_REC); + result2.append(result); + result2.append(gen[j]); + } + freelist(&gen, genl); + } + } else { + result2.push_back(MSEP_REC); + result2.append(result); + if (strstr(pl[k], MORPH_SURF_PFX)) { + std::string field; + copy_field(field, pl[k], MORPH_SURF_PFX); + result2.append(field); + } + std::string field; + copy_field(field, pl[k], MORPH_STEM); + result2.append(field); + } + } + freelist(&pl, pln); + } + int sln = line_tok(result2.c_str(), slst, MSEP_REC); + return uniqlist(*slst, sln); +} + +int Hunspell::stem(char*** slst, const char* word) { + char** pl; + int pln = analyze(&pl, word); + int pln2 = stem(slst, pl, pln); + freelist(&pl, pln); + return pln2; +} + +const char* Hunspell::get_wordchars() { + return pAMgr->get_wordchars(); +} + +const std::vector<w_char>& Hunspell::get_wordchars_utf16() { + return pAMgr->get_wordchars_utf16(); +} + +void Hunspell::mkinitcap(std::string& u8) { + if (utf8) { + std::vector<w_char> u16; + u8_u16(u16, u8); + ::mkinitcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitcap(u8, csconv); + } +} + +int Hunspell::mkinitcap2(std::string& u8, std::vector<w_char>& u16) { + if (utf8) { + ::mkinitcap_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitcap(u8, csconv); + } + return u8.size(); +} + +int Hunspell::mkinitsmall2(std::string& u8, std::vector<w_char>& u16) { + if (utf8) { + ::mkinitsmall_utf(u16, langnum); + u16_u8(u8, u16); + } else { + ::mkinitsmall(u8, csconv); + } + return u8.size(); +} + +int Hunspell::add(const char* word) { + if (pHMgr[0]) + return (pHMgr[0])->add(word); + return 0; +} + +int Hunspell::add_with_affix(const char* word, const char* example) { + if (pHMgr[0]) + return (pHMgr[0])->add_with_affix(word, example); + return 0; +} + +int Hunspell::remove(const char* word) { + if (pHMgr[0]) + return (pHMgr[0])->remove(word); + return 0; +} + +const char* Hunspell::get_version() { + return pAMgr->get_version(); +} + +struct cs_info* Hunspell::get_csconv() { + return csconv; +} + +void Hunspell::cat_result(std::string& result, char* st) { + if (st) { + if (!result.empty()) + result.append("\n"); + result.append(st); + free(st); + } +} + +int Hunspell::analyze(char*** slst, const char* word) { + *slst = NULL; + if (!pSMgr || maxdic == 0) + return 0; + int nc = strlen(word); + if (utf8) { + if (nc >= MAXWORDUTF8LEN) + return 0; + } else { + if (nc >= MAXWORDLEN) + return 0; + } + int captype = NOCAP; + size_t abbv = 0; + size_t wl = 0; + + std::string scw; + std::vector<w_char> sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + { + std::string wspace; + + int convstatus = rl ? rl->conv(word, wspace) : 0; + if (convstatus < 0) + return 0; + else if (convstatus > 0) + wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv); + else + wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv); + } + + if (wl == 0) { + if (abbv) { + scw.clear(); + for (wl = 0; wl < abbv; wl++) + scw.push_back('.'); + abbv = 0; + } else + return 0; + } + + std::string result; + + size_t n = 0; + size_t n2 = 0; + size_t n3 = 0; + + // test numbers + // LANG_hu section: set dash information for suggestions + if (langnum == LANG_hu) { + while ((n < wl) && (((scw[n] <= '9') && (scw[n] >= '0')) || + (((scw[n] == '.') || (scw[n] == ',')) && (n > 0)))) { + n++; + if ((scw[n] == '.') || (scw[n] == ',')) { + if (((n2 == 0) && (n > 3)) || + ((n2 > 0) && ((scw[n - 1] == '.') || (scw[n - 1] == ',')))) + break; + n2++; + n3 = n; + } + } + + if ((n == wl) && (n3 > 0) && (n - n3 > 3)) + return 0; + if ((n == wl) || ((n > 0) && ((scw[n] == '%') || (scw[n] == '\xB0')) && + checkword(scw.c_str() + n, NULL, NULL))) { + result.append(scw); + result.resize(n - 1); + if (n == wl) + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n - 1)); + else { + char sign = scw[n]; + scw[n] = '\0'; + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n - 1)); + result.push_back('+'); // XXX SPEC. MORPHCODE + scw[n] = sign; + cat_result(result, pSMgr->suggest_morph(scw.c_str() + n)); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + // END OF LANG_hu section + + switch (captype) { + case HUHCAP: + case HUHINITCAP: + case NOCAP: { + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + case INITCAP: { + wl = mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + + u8buffer = scw; + u8buffer.push_back('.'); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + case ALLCAP: { + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + mkallsmall2(scw, sunicw); + std::string u8buffer(scw); + mkinitcap2(scw, sunicw); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + cat_result(result, pSMgr->suggest_morph(scw.c_str())); + if (abbv) { + u8buffer.push_back('.'); + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + + u8buffer = scw; + u8buffer.push_back('.'); + + cat_result(result, pSMgr->suggest_morph(u8buffer.c_str())); + } + break; + } + } + + if (!result.empty()) { + // word reversing wrapper for complex prefixes + if (complexprefixes) { + if (utf8) + reverseword_utf(result); + else + reverseword(result); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + + // compound word with dash (HU) I18n + // LANG_hu section: set dash information for suggestions + + size_t dash_pos = langnum == LANG_hu ? scw.find('-') : std::string::npos; + int nresult = 0; + if (dash_pos != std::string::npos) { + std::string part1 = scw.substr(0, dash_pos); + std::string part2 = scw.substr(dash_pos+1); + + // examine 2 sides of the dash + if (part2.empty()) { // base word ending with dash + if (spell(part1.c_str())) { + char* p = pSMgr->suggest_morph(part1.c_str()); + if (p) { + int ret = line_tok(p, slst, MSEP_REC); + free(p); + return ret; + } + } + } else if (part2.size() == 1 && part2[0] == 'e') { // XXX (HU) -e hat. + if (spell(part1.c_str()) && (spell("-e"))) { + char* st = pSMgr->suggest_morph(part1.c_str()); + if (st) { + result.append(st); + free(st); + } + result.push_back('+'); // XXX spec. separator in MORPHCODE + st = pSMgr->suggest_morph("-e"); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } else { + // first word ending with dash: word- XXX ??? + part1.push_back(' '); + nresult = spell(part1.c_str()); + part1.erase(part1.size() - 1); + if (nresult && spell(part2.c_str()) && + ((part2.size() > 1) || ((part2[0] > '0') && (part2[0] < '9')))) { + char* st = pSMgr->suggest_morph(part1.c_str()); + if (st) { + result.append(st); + free(st); + result.push_back('+'); // XXX spec. separator in MORPHCODE + } + st = pSMgr->suggest_morph(part2.c_str()); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + // affixed number in correct word + if (nresult && (dash_pos > 0) && + (((scw[dash_pos - 1] <= '9') && (scw[dash_pos - 1] >= '0')) || + (scw[dash_pos - 1] == '.'))) { + n = 1; + if (scw[dash_pos - n] == '.') + n++; + // search first not a number character to left from dash + while ((dash_pos >= n) && ((scw[dash_pos - n] == '0') || (n < 3)) && + (n < 6)) { + n++; + } + if (dash_pos < n) + n--; + // numbers: valami1000000-hoz + // examine 100000-hoz, 10000-hoz 1000-hoz, 10-hoz, + // 56-hoz, 6-hoz + for (; n >= 1; n--) { + if (scw[dash_pos - n] < '0' || scw[dash_pos - n] > '9') { + continue; + } + std::string chunk = scw.substr(dash_pos - n); + if (checkword(chunk.c_str(), NULL, NULL)) { + result.append(chunk); + char* st = pSMgr->suggest_morph(chunk.c_str()); + if (st) { + result.append(st); + free(st); + } + return line_tok(result.c_str(), slst, MSEP_REC); + } + } + } + } + return 0; +} + +int Hunspell::generate(char*** slst, const char* word, char** pl, int pln) { + *slst = NULL; + if (!pSMgr || !pln) + return 0; + char** pl2; + int pl2n = analyze(&pl2, word); + int captype = NOCAP; + int abbv = 0; + std::string cw; + cleanword(cw, word, &captype, &abbv); + std::string result; + + for (int i = 0; i < pln; i++) { + cat_result(result, pSMgr->suggest_gen(pl2, pl2n, pl[i])); + } + freelist(&pl2, pl2n); + + if (!result.empty()) { + // allcap + if (captype == ALLCAP) + mkallcap(result); + + // line split + int linenum = line_tok(result.c_str(), slst, MSEP_REC); + + // capitalize + if (captype == INITCAP || captype == HUHINITCAP) { + for (int j = 0; j < linenum; j++) { + std::string form((*slst)[j]); + free((*slst)[j]); + mkinitcap(form); + (*slst)[j] = mystrdup(form.c_str()); + } + } + + // temporary filtering of prefix related errors (eg. + // generate("undrinkable", "eats") --> "undrinkables" and "*undrinks") + + int r = 0; + for (int j = 0; j < linenum; j++) { + if (!spell((*slst)[j])) { + free((*slst)[j]); + (*slst)[j] = NULL; + } else { + if (r < j) + (*slst)[r] = (*slst)[j]; + r++; + } + } + if (r > 0) + return r; + free(*slst); + *slst = NULL; + } + return 0; +} + +int Hunspell::generate(char*** slst, const char* word, const char* pattern) { + char** pl; + int pln = analyze(&pl, pattern); + int n = generate(slst, word, pl, pln); + freelist(&pl, pln); + return uniqlist(*slst, n); +} + +// minimal XML parser functions +std::string Hunspell::get_xml_par(const char* par) { + std::string dest; + if (!par) + return dest; + char end = *par; + if (end == '>') + end = '<'; + else if (end != '\'' && end != '"') + return 0; // bad XML + for (par++; *par != '\0' && *par != end; ++par) { + dest.push_back(*par); + } + mystrrep(dest, "<", "<"); + mystrrep(dest, "&", "&"); + return dest; +} + +int Hunspell::get_langnum() const { + return langnum; +} + +int Hunspell::input_conv(const char* word, char* dest, size_t destsize) { + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL; + return (rl && rl->conv(word, dest, destsize) > 0); +} + +// return the beginning of the element (attr == NULL) or the attribute +const char* Hunspell::get_xml_pos(const char* s, const char* attr) { + const char* end = strchr(s, '>'); + const char* p = s; + if (attr == NULL) + return end; + do { + p = strstr(p, attr); + if (!p || p >= end) + return 0; + } while (*(p - 1) != ' ' && *(p - 1) != '\n'); + return p + strlen(attr); +} + +int Hunspell::check_xml_par(const char* q, + const char* attr, + const char* value) { + std::string cw = get_xml_par(get_xml_pos(q, attr)); + if (cw == value) + return 1; + return 0; +} + +int Hunspell::get_xml_list(char*** slst, const char* list, const char* tag) { + if (!list) + return 0; + int n = 0; + const char* p; + for (p = list; ((p = strstr(p, tag)) != NULL); p++) + n++; + if (n == 0) + return 0; + *slst = (char**)malloc(sizeof(char*) * n); + if (!*slst) + return 0; + for (p = list, n = 0; ((p = strstr(p, tag)) != NULL); p++, n++) { + std::string cw = get_xml_par(p + strlen(tag) - 1); + if (cw.empty()) { + break; + } + (*slst)[n] = mystrdup(cw.c_str()); + } + return n; +} + +int Hunspell::spellml(char*** slst, const char* word) { + const char* q = strstr(word, "<query"); + if (!q) + return 0; // bad XML input + const char* q2 = strchr(q, '>'); + if (!q2) + return 0; // bad XML input + q2 = strstr(q2, "<word"); + if (!q2) + return 0; // bad XML input + if (check_xml_par(q, "type=", "analyze")) { + int n = 0; + std::string cw = get_xml_par(strchr(q2, '>')); + if (!cw.empty()) + n = analyze(slst, cw.c_str()); + if (n == 0) + return 0; + // convert the result to <code><a>ana1</a><a>ana2</a></code> format + std::string r; + r.append("<code>"); + for (int i = 0; i < n; i++) { + r.append("<a>"); + + std::string entry((*slst)[i]); + free((*slst)[i]); + mystrrep(entry, "\t", " "); + mystrrep(entry, "&", "&"); + mystrrep(entry, "<", "<"); + r.append(entry); + + r.append("</a>"); + } + r.append("</code>"); + (*slst)[0] = mystrdup(r.c_str()); + return 1; + } else if (check_xml_par(q, "type=", "stem")) { + std::string cw = get_xml_par(strchr(q2, '>')); + if (!cw.empty()) + return stem(slst, cw.c_str()); + } else if (check_xml_par(q, "type=", "generate")) { + std::string cw = get_xml_par(strchr(q2, '>')); + if (cw.empty()) + return 0; + const char* q3 = strstr(q2 + 1, "<word"); + if (q3) { + std::string cw2 = get_xml_par(strchr(q3, '>')); + if (!cw2.empty()) { + return generate(slst, cw.c_str(), cw2.c_str()); + } + } else { + if ((q2 = strstr(q2 + 1, "<code")) != NULL) { + char** slst2; + int n = get_xml_list(&slst2, strchr(q2, '>'), "<a>"); + if (n != 0) { + int n2 = generate(slst, cw.c_str(), slst2, n); + freelist(&slst2, n); + return uniqlist(*slst, n2); + } + freelist(&slst2, n); + } + } + } + return 0; +} + +Hunhandle* Hunspell_create(const char* affpath, const char* dpath) { + return (Hunhandle*)(new Hunspell(affpath, dpath)); +} + +Hunhandle* Hunspell_create_key(const char* affpath, + const char* dpath, + const char* key) { + return (Hunhandle*)(new Hunspell(affpath, dpath, key)); +} + +void Hunspell_destroy(Hunhandle* pHunspell) { + delete (Hunspell*)(pHunspell); +} + +int Hunspell_add_dic(Hunhandle* pHunspell, const char* dpath) { + return ((Hunspell*)pHunspell)->add_dic(dpath); +} + +int Hunspell_spell(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->spell(word); +} + +char* Hunspell_get_dic_encoding(Hunhandle* pHunspell) { + return ((Hunspell*)pHunspell)->get_dic_encoding(); +} + +int Hunspell_suggest(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->suggest(slst, word); +} + +int Hunspell_analyze(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->analyze(slst, word); +} + +int Hunspell_stem(Hunhandle* pHunspell, char*** slst, const char* word) { + return ((Hunspell*)pHunspell)->stem(slst, word); +} + +int Hunspell_stem2(Hunhandle* pHunspell, char*** slst, char** desc, int n) { + return ((Hunspell*)pHunspell)->stem(slst, desc, n); +} + +int Hunspell_generate(Hunhandle* pHunspell, + char*** slst, + const char* word, + const char* word2) { + return ((Hunspell*)pHunspell)->generate(slst, word, word2); +} + +int Hunspell_generate2(Hunhandle* pHunspell, + char*** slst, + const char* word, + char** desc, + int n) { + return ((Hunspell*)pHunspell)->generate(slst, word, desc, n); +} + +/* functions for run-time modification of the dictionary */ + +/* add word to the run-time dictionary */ + +int Hunspell_add(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->add(word); +} + +/* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + +int Hunspell_add_with_affix(Hunhandle* pHunspell, + const char* word, + const char* example) { + return ((Hunspell*)pHunspell)->add_with_affix(word, example); +} + +/* remove word from the run-time dictionary */ + +int Hunspell_remove(Hunhandle* pHunspell, const char* word) { + return ((Hunspell*)pHunspell)->remove(word); +} + +void Hunspell_free_list(Hunhandle*, char*** slst, int n) { + freelist(slst, n); +} + +int Hunspell::suffix_suggest(char*** slst, const char* root_word) { + struct hentry* he = NULL; + int len; + std::string w2; + const char* word; + char* ignoredchars = pAMgr->get_ignore(); + if (ignoredchars != NULL) { + w2.assign(root_word); + if (utf8) { + const std::vector<w_char>& ignoredchars_utf16 = + pAMgr->get_ignore_utf16(); + remove_ignored_chars_utf(w2, ignoredchars_utf16); + } else { + remove_ignored_chars(w2, ignoredchars); + } + word = w2.c_str(); + } else + word = root_word; + + len = strlen(word); + + if (!len) + return 0; + + char** wlst = (char**)malloc(MAXSUGGESTION * sizeof(char*)); + if (wlst == NULL) + return -1; + *slst = wlst; + for (int i = 0; i < MAXSUGGESTION; i++) { + wlst[i] = NULL; + } + + for (int i = 0; (i < maxdic) && !he; i++) { + he = (pHMgr[i])->lookup(word); + } + if (he) { + return pAMgr->get_suffix_words(he->astr, he->alen, root_word, *slst); + } + return 0; +} diff --git a/extensions/spellcheck/hunspell/src/hunspell.h b/extensions/spellcheck/hunspell/src/hunspell.h new file mode 100644 index 000000000..726bbe207 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.h @@ -0,0 +1,162 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MYSPELLMGR_H_ +#define _MYSPELLMGR_H_ + +#include "hunvisapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Hunhandle Hunhandle; + +LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create(const char* affpath, + const char* dpath); + +LIBHUNSPELL_DLL_EXPORTED Hunhandle* Hunspell_create_key(const char* affpath, + const char* dpath, + const char* key); + +LIBHUNSPELL_DLL_EXPORTED void Hunspell_destroy(Hunhandle* pHunspell); + +/* load extra dictionaries (only dic files) + * output: 0 = additional dictionary slots available, 1 = slots are now full*/ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_dic(Hunhandle* pHunspell, + const char* dpath); + +/* spell(word) - spellcheck word + * output: 0 = bad word, not 0 = good word + */ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_spell(Hunhandle* pHunspell, const char*); + +LIBHUNSPELL_DLL_EXPORTED char* Hunspell_get_dic_encoding(Hunhandle* pHunspell); + +/* suggest(suggestions, word) - search suggestions + * input: pointer to an array of strings pointer and the (bad) word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_suggest(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* morphological functions */ + +/* analyze(result, word) - morphological analysis of the word */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_analyze(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* stem(result, word) - stemmer function */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem(Hunhandle* pHunspell, + char*** slst, + const char* word); + +/* stem(result, analysis, n) - get stems from a morph. analysis + * example: + * char ** result, result2; + * int n1 = Hunspell_analyze(result, "words"); + * int n2 = Hunspell_stem2(result2, result, n1); + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_stem2(Hunhandle* pHunspell, + char*** slst, + char** desc, + int n); + +/* generate(result, word, word2) - morphological generation by example(s) */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate(Hunhandle* pHunspell, + char*** slst, + const char* word, + const char* word2); + +/* generate(result, word, desc, n) - generation by morph. description(s) + * example: + * char ** result; + * char * affix = "is:plural"; // description depends from dictionaries, too + * int n = Hunspell_generate2(result, "word", &affix, 1); + * for (int i = 0; i < n; i++) printf("%s\n", result[i]); + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_generate2(Hunhandle* pHunspell, + char*** slst, + const char* word, + char** desc, + int n); + +/* functions for run-time modification of the dictionary */ + +/* add word to the run-time dictionary */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add(Hunhandle* pHunspell, + const char* word); + +/* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_with_affix(Hunhandle* pHunspell, + const char* word, + const char* example); + +/* remove word from the run-time dictionary */ + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_remove(Hunhandle* pHunspell, + const char* word); + +/* free suggestion lists */ + +LIBHUNSPELL_DLL_EXPORTED void Hunspell_free_list(Hunhandle* pHunspell, + char*** slst, + int n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunspell.hxx b/extensions/spellcheck/hunspell/src/hunspell.hxx new file mode 100644 index 000000000..401475309 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunspell.hxx @@ -0,0 +1,258 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hunvisapi.h" + +#include "hashmgr.hxx" +#include "affixmgr.hxx" +#include "suggestmgr.hxx" +#include "langnum.hxx" +#include <vector> + +#define SPELL_XML "<?xml?>" + +#define MAXDIC 20 +#define MAXSUGGESTION 15 +#define MAXSHARPS 5 + +#define HUNSPELL_OK (1 << 0) +#define HUNSPELL_OK_WARN (1 << 1) + +#ifndef _MYSPELLMGR_HXX_ +#define _MYSPELLMGR_HXX_ + +class LIBHUNSPELL_DLL_EXPORTED Hunspell { + private: + Hunspell(const Hunspell&); + Hunspell& operator=(const Hunspell&); + + private: + AffixMgr* pAMgr; + HashMgr* pHMgr[MAXDIC]; + int maxdic; + SuggestMgr* pSMgr; + char* affixpath; + char* encoding; + struct cs_info* csconv; + int langnum; + int utf8; + int complexprefixes; + char** wordbreak; + + public: + /* Hunspell(aff, dic) - constructor of Hunspell class + * input: path of affix file and dictionary file + * + * In WIN32 environment, use UTF-8 encoded paths started with the long path + * prefix \\\\?\\ to handle system-independent character encoding and very + * long path names (without the long path prefix Hunspell will use fopen() + * with system-dependent character encoding instead of _wfopen()). + */ + + Hunspell(const char* affpath, const char* dpath, const char* key = NULL); + ~Hunspell(); + + /* load extra dictionaries (only dic files) */ + int add_dic(const char* dpath, const char* key = NULL); + + /* spell(word) - spellcheck word + * output: 0 = bad word, not 0 = good word + * + * plus output: + * info: information bit array, fields: + * SPELL_COMPOUND = a compound word + * SPELL_FORBIDDEN = an explicit forbidden word + * root: root (stem), when input is a word with affix(es) + */ + + int spell(const char* word, int* info = NULL, char** root = NULL); + + /* suggest(suggestions, word) - search suggestions + * input: pointer to an array of strings pointer and the (bad) word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ + + int suggest(char*** slst, const char* word); + + /* Suggest words from suffix rules + * suffix_suggest(suggestions, root_word) + * input: pointer to an array of strings pointer and the word + * array of strings pointer (here *slst) may not be initialized + * output: number of suggestions in string array, and suggestions in + * a newly allocated array of strings (*slts will be NULL when number + * of suggestion equals 0.) + */ + int suffix_suggest(char*** slst, const char* root_word); + + /* deallocate suggestion lists */ + + void free_list(char*** slst, int n); + + char* get_dic_encoding(); + + /* morphological functions */ + + /* analyze(result, word) - morphological analysis of the word */ + + int analyze(char*** slst, const char* word); + + /* stem(result, word) - stemmer function */ + + int stem(char*** slst, const char* word); + + /* stem(result, analysis, n) - get stems from a morph. analysis + * example: + * char ** result, result2; + * int n1 = analyze(&result, "words"); + * int n2 = stem(&result2, result, n1); + */ + + int stem(char*** slst, char** morph, int n); + + /* generate(result, word, word2) - morphological generation by example(s) */ + + int generate(char*** slst, const char* word, const char* word2); + + /* generate(result, word, desc, n) - generation by morph. description(s) + * example: + * char ** result; + * char * affix = "is:plural"; // description depends from dictionaries, too + * int n = generate(&result, "word", &affix, 1); + * for (int i = 0; i < n; i++) printf("%s\n", result[i]); + */ + + int generate(char*** slst, const char* word, char** desc, int n); + + /* functions for run-time modification of the dictionary */ + + /* add word to the run-time dictionary */ + + int add(const char* word); + + /* add word to the run-time dictionary with affix flags of + * the example (a dictionary word): Hunspell will recognize + * affixed forms of the new word, too. + */ + + int add_with_affix(const char* word, const char* example); + + /* remove word from the run-time dictionary */ + + int remove(const char* word); + + /* other */ + + /* get extra word characters definied in affix file for tokenization */ + const char* get_wordchars(); + const std::vector<w_char>& get_wordchars_utf16(); + + struct cs_info* get_csconv(); + const char* get_version(); + + int get_langnum() const; + + /* need for putdic */ + int input_conv(const char* word, char* dest, size_t destsize); + + private: + void cleanword(std::string& dest, const char*, int* pcaptype, int* pabbrev); + size_t cleanword2(std::string& dest, + std::vector<w_char>& dest_u, + const char*, + int* w_len, + int* pcaptype, + size_t* pabbrev); + void mkinitcap(std::string& u8); + int mkinitcap2(std::string& u8, std::vector<w_char>& u16); + int mkinitsmall2(std::string& u8, std::vector<w_char>& u16); + void mkallcap(std::string& u8); + int mkallsmall2(std::string& u8, std::vector<w_char>& u16); + struct hentry* checkword(const char*, int* info, char** root); + std::string sharps_u8_l1(const std::string& source); + hentry* + spellsharps(std::string& base, size_t start_pos, int, int, int* info, char** root); + int is_keepcase(const hentry* rv); + int insert_sug(char*** slst, const char* word, int ns); + void cat_result(std::string& result, char* st); + char* stem_description(const char* desc); + int spellml(char*** slst, const char* word); + std::string get_xml_par(const char* par); + const char* get_xml_pos(const char* s, const char* attr); + int get_xml_list(char*** slst, const char* list, const char* tag); + int check_xml_par(const char* q, const char* attr, const char* value); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunvisapi.h b/extensions/spellcheck/hunspell/src/hunvisapi.h new file mode 100644 index 000000000..503c20f66 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunvisapi.h @@ -0,0 +1,18 @@ +#ifndef _HUNSPELL_VISIBILITY_H_ +#define _HUNSPELL_VISIBILITY_H_ + +#if defined(HUNSPELL_STATIC) +# define LIBHUNSPELL_DLL_EXPORTED +#elif defined(_MSC_VER) +# if defined(BUILDING_LIBHUNSPELL) +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllexport) +# else +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBHUNSPELL) && 1 +# define LIBHUNSPELL_DLL_EXPORTED __attribute__((__visibility__("default"))) +#else +# define LIBHUNSPELL_DLL_EXPORTED +#endif + +#endif diff --git a/extensions/spellcheck/hunspell/src/hunzip.cxx b/extensions/spellcheck/hunspell/src/hunzip.cxx new file mode 100644 index 000000000..b2788a105 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunzip.cxx @@ -0,0 +1,263 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "hunzip.hxx" +#include "csutil.hxx" + +#define CODELEN 65536 +#define BASEBITREC 5000 + +#define UNCOMPRESSED '\002' +#define MAGIC "hz0" +#define MAGIC_ENCRYPT "hz1" +#define MAGICLEN (sizeof(MAGIC) - 1) + +int Hunzip::fail(const char* err, const char* par) { + fprintf(stderr, err, par); + return -1; +} + +Hunzip::Hunzip(const char* file, const char* key) + : fin(NULL), bufsiz(0), lastbit(0), inc(0), inbits(0), outc(0), dec(NULL) { + in[0] = out[0] = line[0] = '\0'; + filename = mystrdup(file); + if (getcode(key) == -1) + bufsiz = -1; + else + bufsiz = getbuf(); +} + +int Hunzip::getcode(const char* key) { + unsigned char c[2]; + int i, j, n, p; + int allocatedbit = BASEBITREC; + const char* enc = key; + + if (!filename) + return -1; + + fin = myfopen(filename, "rb"); + if (!fin) + return -1; + + // read magic number + if ((fread(in, 1, 3, fin) < MAGICLEN) || + !(strncmp(MAGIC, in, MAGICLEN) == 0 || + strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0)) { + return fail(MSG_FORMAT, filename); + } + + // check encryption + if (strncmp(MAGIC_ENCRYPT, in, MAGICLEN) == 0) { + unsigned char cs; + if (!key) + return fail(MSG_KEY, filename); + if (fread(&c, 1, 1, fin) < 1) + return fail(MSG_FORMAT, filename); + for (cs = 0; *enc; enc++) + cs ^= *enc; + if (cs != c[0]) + return fail(MSG_KEY, filename); + enc = key; + } else + key = NULL; + + // read record count + if (fread(&c, 1, 2, fin) < 2) + return fail(MSG_FORMAT, filename); + + if (key) { + c[0] ^= *enc; + if (*(++enc) == '\0') + enc = key; + c[1] ^= *enc; + } + + n = ((int)c[0] << 8) + c[1]; + dec = (struct bit*)malloc(BASEBITREC * sizeof(struct bit)); + if (!dec) + return fail(MSG_MEMORY, filename); + dec[0].v[0] = 0; + dec[0].v[1] = 0; + + // read codes + for (i = 0; i < n; i++) { + unsigned char l; + if (fread(c, 1, 2, fin) < 2) + return fail(MSG_FORMAT, filename); + if (key) { + if (*(++enc) == '\0') + enc = key; + c[0] ^= *enc; + if (*(++enc) == '\0') + enc = key; + c[1] ^= *enc; + } + if (fread(&l, 1, 1, fin) < 1) + return fail(MSG_FORMAT, filename); + if (key) { + if (*(++enc) == '\0') + enc = key; + l ^= *enc; + } + if (fread(in, 1, l / 8 + 1, fin) < (size_t)l / 8 + 1) + return fail(MSG_FORMAT, filename); + if (key) + for (j = 0; j <= l / 8; j++) { + if (*(++enc) == '\0') + enc = key; + in[j] ^= *enc; + } + p = 0; + for (j = 0; j < l; j++) { + int b = (in[j / 8] & (1 << (7 - (j % 8)))) ? 1 : 0; + int oldp = p; + p = dec[p].v[b]; + if (p == 0) { + lastbit++; + if (lastbit == allocatedbit) { + allocatedbit += BASEBITREC; + dec = (struct bit*)realloc(dec, allocatedbit * sizeof(struct bit)); + } + dec[lastbit].v[0] = 0; + dec[lastbit].v[1] = 0; + dec[oldp].v[b] = lastbit; + p = lastbit; + } + } + dec[p].c[0] = c[0]; + dec[p].c[1] = c[1]; + } + return 0; +} + +Hunzip::~Hunzip() { + if (dec) + free(dec); + if (fin) + fclose(fin); + if (filename) + free(filename); +} + +int Hunzip::getbuf() { + int p = 0; + int o = 0; + do { + if (inc == 0) + inbits = fread(in, 1, BUFSIZE, fin) * 8; + for (; inc < inbits; inc++) { + int b = (in[inc / 8] & (1 << (7 - (inc % 8)))) ? 1 : 0; + int oldp = p; + p = dec[p].v[b]; + if (p == 0) { + if (oldp == lastbit) { + fclose(fin); + fin = NULL; + // add last odd byte + if (dec[lastbit].c[0]) + out[o++] = dec[lastbit].c[1]; + return o; + } + out[o++] = dec[oldp].c[0]; + out[o++] = dec[oldp].c[1]; + if (o == BUFSIZE) + return o; + p = dec[p].v[b]; + } + } + inc = 0; + } while (inbits == BUFSIZE * 8); + return fail(MSG_FORMAT, filename); +} + +const char* Hunzip::getline() { + char linebuf[BUFSIZE]; + int l = 0, eol = 0, left = 0, right = 0; + if (bufsiz == -1) + return NULL; + while (l < bufsiz && !eol) { + linebuf[l++] = out[outc]; + switch (out[outc]) { + case '\t': + break; + case 31: { // escape + if (++outc == bufsiz) { + bufsiz = getbuf(); + outc = 0; + } + linebuf[l - 1] = out[outc]; + break; + } + case ' ': + break; + default: + if (((unsigned char)out[outc]) < 47) { + if (out[outc] > 32) { + right = out[outc] - 31; + if (++outc == bufsiz) { + bufsiz = getbuf(); + outc = 0; + } + } + if (out[outc] == 30) + left = 9; + else + left = out[outc]; + linebuf[l - 1] = '\n'; + eol = 1; + } + } + if (++outc == bufsiz) { + outc = 0; + bufsiz = fin ? getbuf() : -1; + } + } + if (right) + strcpy(linebuf + l - 1, line + strlen(line) - right - 1); + else + linebuf[l] = '\0'; + strcpy(line + left, linebuf); + return line; +} diff --git a/extensions/spellcheck/hunspell/src/hunzip.hxx b/extensions/spellcheck/hunspell/src/hunzip.hxx new file mode 100644 index 000000000..5082adddb --- /dev/null +++ b/extensions/spellcheck/hunspell/src/hunzip.hxx @@ -0,0 +1,87 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* hunzip: file decompression for sorted dictionaries with optional encryption, + * algorithm: prefix-suffix encoding and 16-bit Huffman encoding */ + +#ifndef _HUNZIP_HXX_ +#define _HUNZIP_HXX_ + +#include "hunvisapi.h" + +#include <stdio.h> + +#define BUFSIZE 65536 +#define HZIP_EXTENSION ".hz" + +#define MSG_OPEN "error: %s: cannot open\n" +#define MSG_FORMAT "error: %s: not in hzip format\n" +#define MSG_MEMORY "error: %s: missing memory\n" +#define MSG_KEY "error: %s: missing or bad password\n" + +struct bit { + unsigned char c[2]; + int v[2]; +}; + +class LIBHUNSPELL_DLL_EXPORTED Hunzip { + private: + Hunzip(const Hunzip&); + Hunzip& operator=(const Hunzip&); + + protected: + char* filename; + FILE* fin; + int bufsiz, lastbit, inc, inbits, outc; + struct bit* dec; // code table + char in[BUFSIZE]; // input buffer + char out[BUFSIZE + 1]; // Huffman-decoded buffer + char line[BUFSIZE + 50]; // decoded line + int getcode(const char* key); + int getbuf(); + int fail(const char* err, const char* par); + + public: + Hunzip(const char* filename, const char* key = NULL); + ~Hunzip(); + const char* getline(); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/langnum.hxx b/extensions/spellcheck/hunspell/src/langnum.hxx new file mode 100644 index 000000000..af5c86e4f --- /dev/null +++ b/extensions/spellcheck/hunspell/src/langnum.hxx @@ -0,0 +1,78 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _LANGNUM_HXX_ +#define _LANGNUM_HXX_ + +/* + language numbers for language specific codes + see http://l10n.openoffice.org/languages.html +*/ + +enum { + LANG_ar = 96, + LANG_az = 100, // custom number + LANG_bg = 41, + LANG_ca = 37, + LANG_cs = 42, + LANG_da = 45, + LANG_de = 49, + LANG_el = 30, + LANG_en = 01, + LANG_es = 34, + LANG_eu = 10, + LANG_fr = 02, + LANG_gl = 38, + LANG_hr = 78, + LANG_hu = 36, + LANG_it = 39, + LANG_la = 99, // custom number + LANG_lv = 101, // custom number + LANG_nl = 31, + LANG_pl = 48, + LANG_pt = 03, + LANG_ru = 07, + LANG_sv = 50, + LANG_tr = 90, + LANG_uk = 80, + LANG_xx = 999 +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/license.hunspell b/extensions/spellcheck/hunspell/src/license.hunspell new file mode 100644 index 000000000..dc2ce9c1e --- /dev/null +++ b/extensions/spellcheck/hunspell/src/license.hunspell @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Laszlo Nemeth (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): + * David Einstein + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll Janos + * Biro Arpad + * Goldman Eleonora + * Sarlos Tamas + * Bencsath Boldizsar + * Halacsy Peter + * Dvornik Laszlo + * Gefferth Andras + * Nagy Viktor + * Varga Daniel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkanen + * Andras Timar + * Tor Lillqvist + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_CLIENT +# include "config.h" +#endif diff --git a/extensions/spellcheck/hunspell/src/license.myspell b/extensions/spellcheck/hunspell/src/license.myspell new file mode 100644 index 000000000..2da533075 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/license.myspell @@ -0,0 +1,61 @@ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * NOTE: A special thanks and credit goes to Geoff Kuenning + * the creator of ispell. MySpell's affix algorithms were + * based on those of ispell which should be noted is + * copyright Geoff Kuenning et.al. and now available + * under a BSD style license. For more information on ispell + * and affix compression in general, please see: + * http://www.cs.ucla.edu/ficus-members/geoff/ispell.html + * (the home page for ispell) + * + * An almost complete rewrite of MySpell for use by + * the Mozilla project has been developed by David Einstein + * (Deinst@world.std.com). David and I are now + * working on parallel development tracks to help + * our respective projects (Mozilla and OpenOffice.org + * and we will maintain full affix file and dictionary + * file compatibility and work on merging our versions + * of MySpell back into a single tree. David has been + * a significant help in improving MySpell. + * + * Special thanks also go to La'szlo' Ne'meth + * <nemethl@gyorsposta.hu> who is the author of the + * Hungarian dictionary and who developed and contributed + * the code to support compound words in MySpell + * and fixed numerous problems with the encoding + * case conversion tables. + * + */ diff --git a/extensions/spellcheck/hunspell/src/moz.build b/extensions/spellcheck/hunspell/src/moz.build new file mode 100644 index 000000000..017264643 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/moz.build @@ -0,0 +1,38 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'affentry.cxx', + 'affixmgr.cxx', + 'csutil.cxx', + 'filemgr.cxx', + 'hashmgr.cxx', + 'hunspell.cxx', + 'hunzip.cxx', + 'phonet.cxx', + 'replist.cxx', + 'suggestmgr.cxx', +] + +# This variable is referenced in configure.in. Make sure to change that file +# too if you need to change this variable. +DEFINES['HUNSPELL_STATIC'] = True + +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '../glue', +] + +# We allow warnings for third-party code that can be updated from upstream. +ALLOW_COMPILER_WARNINGS = True + +include('/ipc/chromium/chromium-config.mozbuild') + +if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']: + CXXFLAGS += [ + '-Wno-implicit-fallthrough', + ] diff --git a/extensions/spellcheck/hunspell/src/patches/1322666 b/extensions/spellcheck/hunspell/src/patches/1322666 new file mode 100644 index 000000000..16db1fbe6 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/patches/1322666 @@ -0,0 +1,24 @@ +Bug 1322666 - Change MAXWORDLEN to 100 + +diff --git a/extensions/spellcheck/hunspell/src/hunspell.cxx b/extensions/spellcheck/hunspell/src/hunspell.cxx +--- a/extensions/spellcheck/hunspell/src/hunspell.cxx ++++ b/extensions/spellcheck/hunspell/src/hunspell.cxx +@@ -80,17 +80,17 @@ + #ifndef MOZILLA_CLIENT + #include "config.h" + #endif + #include "csutil.hxx" + + #include <limits> + #include <string> + +-#define MAXWORDLEN 176 ++#define MAXWORDLEN 100 + #define MAXWORDUTF8LEN (MAXWORDLEN * 3) + + Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) { + encoding = NULL; + csconv = NULL; + utf8 = 0; + complexprefixes = 0; + affixpath = mystrdup(affpath); diff --git a/extensions/spellcheck/hunspell/src/phonet.cxx b/extensions/spellcheck/hunspell/src/phonet.cxx new file mode 100644 index 000000000..17350e74a --- /dev/null +++ b/extensions/spellcheck/hunspell/src/phonet.cxx @@ -0,0 +1,274 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation; + + 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, see + <http://www.gnu.org/licenses/>. + + Changelog: + + 2000-01-05 Bjoern Jacke <bjoern at j3e.de> + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke <bjoern at j3e.de> + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth <nemeth at OOo> + Porting from Aspell to Hunspell using C-like structs +*/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "csutil.hxx" +#include "phonet.hxx" + +void init_phonet_hash(phonetable& parms) { + int i, k; + + for (i = 0; i < HASHSIZE; i++) { + parms.hash[i] = -1; + } + + for (i = 0; parms.rules[i][0] != '\0'; i += 2) { + /** set hash value **/ + k = (unsigned char)parms.rules[i][0]; + + if (parms.hash[k] < 0) { + parms.hash[k] = i; + } + } +} + +// like strcpy but safe if the strings overlap +// but only if dest < src +static inline void strmove(char* dest, char* src) { + while (*src) + *dest++ = *src++; + *dest = '\0'; +} + +static int myisalpha(char ch) { + if ((unsigned char)ch < 128) + return isalpha(ch); + return 1; +} + +/* Do phonetic transformation. */ +/* phonetic transcription algorithm */ +/* see: http://aspell.net/man-html/Phonetic-Code.html */ +/* convert string to uppercase before this call */ +std::string phonet(const std::string& inword, phonetable& parms) { + + int i, k = 0, p, z; + int k0, n0, p0 = -333, z0; + char c; + const char* s; + typedef unsigned char uchar; + + size_t len = inword.size(); + if (len > MAXPHONETUTF8LEN) + return std::string(); + char word[MAXPHONETUTF8LEN + 1]; + strncpy(word, inword.c_str(), MAXPHONETUTF8LEN); + word[MAXPHONETUTF8LEN] = '\0'; + + std::string target; + /** check word **/ + i = z = 0; + while ((c = word[i]) != '\0') { + int n = parms.hash[(uchar)c]; + z0 = 0; + + if (n >= 0) { + /** check all rules for the same letter **/ + while (parms.rules[n][0] == c) { + /** check whole string **/ + k = 1; /** number of found letters **/ + p = 5; /** default priority **/ + s = parms.rules[n]; + s++; /** important for (see below) "*(s-1)" **/ + + while (*s != '\0' && word[i + k] == *s && !isdigit((unsigned char)*s) && + strchr("(-<^$", *s) == NULL) { + k++; + s++; + } + if (*s == '(') { + /** check letters in "(..)" **/ + if (myisalpha(word[i + k]) // ...could be implied? + && strchr(s + 1, word[i + k]) != NULL) { + k++; + while (*s != ')') + s++; + s++; + } + } + p0 = (int)*s; + k0 = k; + while (*s == '-' && k > 1) { + k--; + s++; + } + if (*s == '<') + s++; + if (isdigit((unsigned char)*s)) { + /** determine priority **/ + p = *s - '0'; + s++; + } + if (*s == '^' && *(s + 1) == '^') + s++; + + if (*s == '\0' || (*s == '^' && (i == 0 || !myisalpha(word[i - 1])) && + (*(s + 1) != '$' || (!myisalpha(word[i + k0])))) || + (*s == '$' && i > 0 && myisalpha(word[i - 1]) && + (!myisalpha(word[i + k0])))) { + /** search for followup rules, if: **/ + /** parms.followup and k > 1 and NO '-' in searchstring **/ + char c0 = word[i + k - 1]; + n0 = parms.hash[(uchar)c0]; + + // if (parms.followup && k > 1 && n0 >= 0 + if (k > 1 && n0 >= 0 && p0 != (int)'-' && word[i + k] != '\0') { + /** test follow-up rule for "word[i+k]" **/ + while (parms.rules[n0][0] == c0) { + /** check whole string **/ + k0 = k; + p0 = 5; + s = parms.rules[n0]; + s++; + while (*s != '\0' && word[i + k0] == *s && + !isdigit((unsigned char)*s) && + strchr("(-<^$", *s) == NULL) { + k0++; + s++; + } + if (*s == '(') { + /** check letters **/ + if (myisalpha(word[i + k0]) && + strchr(s + 1, word[i + k0]) != NULL) { + k0++; + while (*s != ')' && *s != '\0') + s++; + if (*s == ')') + s++; + } + } + while (*s == '-') { + /** "k0" gets NOT reduced **/ + /** because "if (k0 == k)" **/ + s++; + } + if (*s == '<') + s++; + if (isdigit((unsigned char)*s)) { + p0 = *s - '0'; + s++; + } + + if (*s == '\0' + /** *s == '^' cuts **/ + || (*s == '$' && !myisalpha(word[i + k0]))) { + if (k0 == k) { + /** this is just a piece of the string **/ + n0 += 2; + continue; + } + + if (p0 < p) { + /** priority too low **/ + n0 += 2; + continue; + } + /** rule fits; stop search **/ + break; + } + n0 += 2; + } /** End of "while (parms.rules[n0][0] == c0)" **/ + + if (p0 >= p && parms.rules[n0][0] == c0) { + n += 2; + continue; + } + } /** end of follow-up stuff **/ + + /** replace string **/ + s = parms.rules[n + 1]; + p0 = (parms.rules[n][0] != '\0' && + strchr(parms.rules[n] + 1, '<') != NULL) + ? 1 + : 0; + if (p0 == 1 && z == 0) { + /** rule with '<' is used **/ + if (!target.empty() && *s != '\0' && + (target[target.size()-1] == c || target[target.size()-1] == *s)) { + target.erase(target.size() - 1); + } + z0 = 1; + z = 1; + k0 = 0; + while (*s != '\0' && word[i + k0] != '\0') { + word[i + k0] = *s; + k0++; + s++; + } + if (k > k0) + strmove(&word[0] + i + k0, &word[0] + i + k); + + /** new "actual letter" **/ + c = word[i]; + } else { /** no '<' rule used **/ + i += k - 1; + z = 0; + while (*s != '\0' && *(s + 1) != '\0' && target.size() < len) { + if (target.empty() || target[target.size()-1] != *s) { + target.push_back(*s); + } + s++; + } + /** new "actual letter" **/ + c = *s; + if (parms.rules[n][0] != '\0' && + strstr(parms.rules[n] + 1, "^^") != NULL) { + if (c != '\0') { + target.push_back(c); + } + strmove(&word[0], &word[0] + i + 1); + i = 0; + z0 = 1; + } + } + break; + } /** end of follow-up stuff **/ + n += 2; + } /** end of while (parms.rules[n][0] == c) **/ + } /** end of if (n >= 0) **/ + if (z0 == 0) { + if (k && !p0 && target.size() < len && c != '\0' && + (1 || target.empty() || target[target.size()-1] != c)) { + /** condense only double letters **/ + target.push_back(c); + /// printf("\n setting \n"); + } + + i++; + z = 0; + k = 0; + } + } /** end of while ((c = word[i]) != '\0') **/ + + return target; +} /** end of function "phonet" **/ diff --git a/extensions/spellcheck/hunspell/src/phonet.hxx b/extensions/spellcheck/hunspell/src/phonet.hxx new file mode 100644 index 000000000..eb9fd0c62 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/phonet.hxx @@ -0,0 +1,52 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation; + + 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, see + <http://www.gnu.org/licenses/>. + + Changelog: + + 2000-01-05 Bjoern Jacke <bjoern at j3e.de> + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke <bjoern at j3e.de> + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth <nemeth at OOo> + Porting from Aspell to Hunspell using C-like structs +*/ + +#ifndef __PHONETHXX__ +#define __PHONETHXX__ + +#define HASHSIZE 256 +#define MAXPHONETLEN 256 +#define MAXPHONETUTF8LEN (MAXPHONETLEN * 4) + +#include "hunvisapi.h" + +struct phonetable { + char utf8; + cs_info* lang; + int num; + char** rules; + int hash[HASHSIZE]; +}; + +LIBHUNSPELL_DLL_EXPORTED void init_phonet_hash(phonetable& parms); + +LIBHUNSPELL_DLL_EXPORTED std::string phonet(const std::string& inword, + phonetable& phone); + +#endif diff --git a/extensions/spellcheck/hunspell/src/replist.cxx b/extensions/spellcheck/hunspell/src/replist.cxx new file mode 100644 index 000000000..b3e6b37d2 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/replist.cxx @@ -0,0 +1,193 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <limits> + +#include "replist.hxx" +#include "csutil.hxx" + +RepList::RepList(int n) { + dat = (replentry**)malloc(sizeof(replentry*) * n); + if (dat == 0) + size = 0; + else + size = n; + pos = 0; +} + +RepList::~RepList() { + for (int i = 0; i < pos; i++) { + free(dat[i]->pattern); + free(dat[i]->pattern2); + free(dat[i]); + } + free(dat); +} + +int RepList::get_pos() { + return pos; +} + +replentry* RepList::item(int n) { + return dat[n]; +} + +int RepList::near(const char* word) { + int p1 = 0; + int p2 = pos; + while ((p2 - p1) > 1) { + int m = (p1 + p2) / 2; + int c = strcmp(word, dat[m]->pattern); + if (c <= 0) { + if (c < 0) + p2 = m; + else + p1 = p2 = m; + } else + p1 = m; + } + return p1; +} + +int RepList::match(const char* word, int n) { + if (strncmp(word, dat[n]->pattern, strlen(dat[n]->pattern)) == 0) + return strlen(dat[n]->pattern); + return 0; +} + +int RepList::add(char* pat1, char* pat2) { + if (pos >= size || pat1 == NULL || pat2 == NULL) + return 1; + replentry* r = (replentry*)malloc(sizeof(replentry)); + if (r == NULL) + return 1; + r->pattern = mystrrep(pat1, "_", " "); + r->pattern2 = mystrrep(pat2, "_", " "); + r->start = false; + r->end = false; + dat[pos++] = r; + for (int i = pos - 1; i > 0; i--) { + r = dat[i]; + if (strcmp(r->pattern, dat[i - 1]->pattern) < 0) { + dat[i] = dat[i - 1]; + dat[i - 1] = r; + } else + break; + } + return 0; +} + +int RepList::conv(const char* word, char* dest, size_t destsize) { + size_t stl = 0; + int change = 0; + for (size_t i = 0; i < strlen(word); i++) { + int n = near(word + i); + int l = match(word + i, n); + if (l) { + size_t replen = strlen(dat[n]->pattern2); + if (stl + replen >= destsize) + return -1; + strcpy(dest + stl, dat[n]->pattern2); + stl += replen; + i += l - 1; + change = 1; + } else { + if (stl + 1 >= destsize) + return -1; + dest[stl++] = word[i]; + } + } + dest[stl] = '\0'; + return change; +} + +bool RepList::conv(const char* word, std::string& dest) { + dest.clear(); + + bool change = false; + for (size_t i = 0; i < strlen(word); i++) { + int n = near(word + i); + int l = match(word + i, n); + if (l) { + dest.append(dat[n]->pattern2); + i += l - 1; + change = true; + } else { + dest.push_back(word[i]); + } + } + return change; +} diff --git a/extensions/spellcheck/hunspell/src/replist.hxx b/extensions/spellcheck/hunspell/src/replist.hxx new file mode 100644 index 000000000..0c5153625 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/replist.hxx @@ -0,0 +1,107 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* string replacement list class */ +#ifndef _REPLIST_HXX_ +#define _REPLIST_HXX_ + +#include "hunvisapi.h" + +#include "w_char.hxx" + +#include <string> +#include <vector> + +class LIBHUNSPELL_DLL_EXPORTED RepList { + private: + RepList(const RepList&); + RepList& operator=(const RepList&); + + protected: + replentry** dat; + int size; + int pos; + + public: + RepList(int n); + ~RepList(); + + int get_pos(); + int add(char* pat1, char* pat2); + replentry* item(int n); + int near(const char* word); + int match(const char* word, int n); + int conv(const char* word, char* dest, size_t destsize); + bool conv(const char* word, std::string& dest); +}; +#endif diff --git a/extensions/spellcheck/hunspell/src/suggestmgr.cxx b/extensions/spellcheck/hunspell/src/suggestmgr.cxx new file mode 100644 index 000000000..17becd758 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/suggestmgr.cxx @@ -0,0 +1,2192 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "suggestmgr.hxx" +#include "htypes.hxx" +#include "csutil.hxx" + +const w_char W_VLINE = {'\0', '|'}; + +SuggestMgr::SuggestMgr(const char* tryme, int maxn, AffixMgr* aptr) { + // register affix manager and check in string of chars to + // try when building candidate suggestions + pAMgr = aptr; + + csconv = NULL; + + ckeyl = 0; + ckey = NULL; + ckey_utf = NULL; + + ctryl = 0; + ctry = NULL; + ctry_utf = NULL; + + utf8 = 0; + langnum = 0; + complexprefixes = 0; + + maxSug = maxn; + nosplitsugs = 0; + maxngramsugs = MAXNGRAMSUGS; + maxcpdsugs = MAXCOMPOUNDSUGS; + + if (pAMgr) { + langnum = pAMgr->get_langnum(); + ckey = pAMgr->get_key_string(); + nosplitsugs = pAMgr->get_nosplitsugs(); + if (pAMgr->get_maxngramsugs() >= 0) + maxngramsugs = pAMgr->get_maxngramsugs(); + utf8 = pAMgr->get_utf8(); + if (pAMgr->get_maxcpdsugs() >= 0) + maxcpdsugs = pAMgr->get_maxcpdsugs(); + if (!utf8) { + char* enc = pAMgr->get_encoding(); + csconv = get_current_cs(enc); + free(enc); + } + complexprefixes = pAMgr->get_complexprefixes(); + } + + if (ckey) { + if (utf8) { + std::vector<w_char> t; + ckeyl = u8_u16(t, ckey); + ckey_utf = (w_char*)malloc(ckeyl * sizeof(w_char)); + if (ckey_utf) + memcpy(ckey_utf, &t[0], ckeyl * sizeof(w_char)); + else + ckeyl = 0; + } else { + ckeyl = strlen(ckey); + } + } + + if (tryme) { + ctry = mystrdup(tryme); + if (ctry) + ctryl = strlen(ctry); + if (ctry && utf8) { + std::vector<w_char> t; + ctryl = u8_u16(t, tryme); + ctry_utf = (w_char*)malloc(ctryl * sizeof(w_char)); + if (ctry_utf) + memcpy(ctry_utf, &t[0], ctryl * sizeof(w_char)); + else + ctryl = 0; + } + } +} + +SuggestMgr::~SuggestMgr() { + pAMgr = NULL; + if (ckey) + free(ckey); + ckey = NULL; + if (ckey_utf) + free(ckey_utf); + ckey_utf = NULL; + ckeyl = 0; + if (ctry) + free(ctry); + ctry = NULL; + if (ctry_utf) + free(ctry_utf); + ctry_utf = NULL; + ctryl = 0; + maxSug = 0; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +int SuggestMgr::testsug(char** wlst, + const char* candidate, + int wl, + int ns, + int cpdsuggest, + int* timer, + clock_t* timelimit) { + int cwrd = 1; + if (ns == maxSug) + return maxSug; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if ((cwrd) && checkword(candidate, wl, cpdsuggest, timer, timelimit)) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + for (int j = 0; j < ns; j++) + free(wlst[j]); + return -1; + } + ns++; + } + return ns; +} + +// generate suggestions for a misspelled word +// pass in address of array of char * pointers +// onlycompoundsug: probably bad suggestions (need for ngram sugs, too) + +int SuggestMgr::suggest(char*** slst, + const char* w, + int nsug, + int* onlycompoundsug) { + int nocompoundtwowords = 0; + char** wlst; + std::vector<w_char> word_utf; + int wl = 0; + int nsugorig = nsug; + std::string w2; + const char* word = w; + int oldSug = 0; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + if (*slst) { + wlst = *slst; + } else { + wlst = (char**)malloc(maxSug * sizeof(char*)); + if (wlst == NULL) + return -1; + for (int i = 0; i < maxSug; i++) { + wlst[i] = NULL; + } + } + + if (utf8) { + wl = u8_u16(word_utf, word); + if (wl == -1) { + *slst = wlst; + return nsug; + } + } + + for (int cpdsuggest = 0; (cpdsuggest < 2) && (nocompoundtwowords == 0); + cpdsuggest++) { + // limit compound suggestion + if (cpdsuggest > 0) + oldSug = nsug; + + // suggestions for an uppercase word (html -> HTML) + if ((nsug < maxSug) && (nsug > -1)) { + nsug = (utf8) ? capchars_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : capchars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we made a typical fault of spelling + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = replchars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we made chose the wrong char from a related set + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = mapchars(wlst, word, nsug, cpdsuggest); + } + + // only suggest compound words when no other suggestion + if ((cpdsuggest == 0) && (nsug > nsugorig)) + nocompoundtwowords = 1; + + // did we swap the order of chars by mistake + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? swapchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : swapchar(wlst, word, nsug, cpdsuggest); + } + + // did we swap the order of non adjacent chars by mistake + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? longswapchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : longswapchar(wlst, word, nsug, cpdsuggest); + } + + // did we just hit the wrong key in place of a good char (case and keyboard) + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? badcharkey_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : badcharkey(wlst, word, nsug, cpdsuggest); + } + + // did we add a char that should not be there + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? extrachar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : extrachar(wlst, word, nsug, cpdsuggest); + } + + // did we forgot a char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? forgotchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : forgotchar(wlst, word, nsug, cpdsuggest); + } + + // did we move a char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? movechar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : movechar(wlst, word, nsug, cpdsuggest); + } + + // did we just hit the wrong key in place of a good char + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? badchar_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : badchar(wlst, word, nsug, cpdsuggest); + } + + // did we double two characters + if ((nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = (utf8) ? doubletwochars_utf(wlst, &word_utf[0], wl, nsug, cpdsuggest) + : doubletwochars(wlst, word, nsug, cpdsuggest); + } + + // perhaps we forgot to hit space and two words ran together + if (!nosplitsugs && (nsug < maxSug) && (nsug > -1) && + (!cpdsuggest || (nsug < oldSug + maxcpdsugs))) { + nsug = twowords(wlst, word, nsug, cpdsuggest); + } + + } // repeating ``for'' statement compounding support + + if (nsug < 0) { + // we ran out of memory - we should free up as much as possible + for (int i = 0; i < maxSug; i++) + if (wlst[i] != NULL) + free(wlst[i]); + free(wlst); + wlst = NULL; + } + + if (!nocompoundtwowords && (nsug > 0) && onlycompoundsug) + *onlycompoundsug = 1; + + *slst = wlst; + return nsug; +} + +// suggestions for an uppercase word (html -> HTML) +int SuggestMgr::capchars_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + mkallcap_utf(candidate_utf, langnum); + std::string candidate; + u16_u8(candidate, candidate_utf); + return testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); +} + +// suggestions for an uppercase word (html -> HTML) +int SuggestMgr::capchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + mkallcap(candidate, csconv); + return testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); +} + +// suggestions for when chose the wrong char out of a related set +int SuggestMgr::mapchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate; + clock_t timelimit; + int timer; + + int wl = strlen(word); + if (wl < 2 || !pAMgr) + return ns; + + int nummap = pAMgr->get_nummap(); + struct mapentry* maptable = pAMgr->get_maptable(); + if (maptable == NULL) + return ns; + + timelimit = clock(); + timer = MINTIMER; + return map_related(word, candidate, 0, wlst, cpdsuggest, ns, + maptable, nummap, &timer, &timelimit); +} + +int SuggestMgr::map_related(const char* word, + std::string& candidate, + int wn, + char** wlst, + int cpdsuggest, + int ns, + const mapentry* maptable, + int nummap, + int* timer, + clock_t* timelimit) { + if (*(word + wn) == '\0') { + int cwrd = 1; + for (int m = 0; m < ns; m++) { + if (candidate == wlst[m]) { + cwrd = 0; + break; + } + } + if ((cwrd) && checkword(candidate.c_str(), candidate.size(), cpdsuggest, timer, timelimit)) { + if (ns < maxSug) { + wlst[ns] = mystrdup(candidate.c_str()); + if (wlst[ns] == NULL) + return -1; + ns++; + } + } + return ns; + } + int in_map = 0; + for (int j = 0; j < nummap; j++) { + for (int k = 0; k < maptable[j].len; k++) { + int len = strlen(maptable[j].set[k]); + if (strncmp(maptable[j].set[k], word + wn, len) == 0) { + in_map = 1; + size_t cn = candidate.size(); + for (int l = 0; l < maptable[j].len; l++) { + candidate.resize(cn); + candidate.append(maptable[j].set[l]); + ns = map_related(word, candidate, wn + len, wlst, + cpdsuggest, ns, maptable, nummap, timer, timelimit); + if (!(*timer)) + return ns; + } + } + } + } + if (!in_map) { + candidate.push_back(*(word + wn)); + ns = map_related(word, candidate, wn + 1, wlst, cpdsuggest, ns, + maptable, nummap, timer, timelimit); + } + return ns; +} + +// suggestions for a typical fault of spelling, that +// differs with more, than 1 letter from the right form. +int SuggestMgr::replchars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate; + int wl = strlen(word); + if (wl < 2 || !pAMgr) + return ns; + int numrep = pAMgr->get_numrep(); + struct replentry* reptable = pAMgr->get_reptable(); + if (reptable == NULL) + return ns; + for (int i = 0; i < numrep; i++) { + const char* r = word; + // search every occurence of the pattern in the word + while ((r = strstr(r, reptable[i].pattern)) != NULL && + (!reptable[i].end || strlen(r) == strlen(reptable[i].pattern)) && + (!reptable[i].start || r == word)) { + candidate.assign(word); + candidate.resize(r - word); + candidate.append(reptable[i].pattern2); + int lenp = strlen(reptable[i].pattern); + candidate.append(r + lenp); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + // check REP suggestions with space + size_t sp = candidate.find(' '); + if (sp != std::string::npos) { + size_t prev = 0; + while (sp != std::string::npos) { + std::string prev_chunk = candidate.substr(prev, sp - prev); + if (checkword(prev_chunk.c_str(), prev_chunk.size(), 0, NULL, NULL)) { + int oldns = ns; + std::string post_chunk = candidate.substr(sp + 1); + ns = testsug(wlst, post_chunk.c_str(), post_chunk.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + if (oldns < ns) { + free(wlst[ns - 1]); + wlst[ns - 1] = mystrdup(candidate.c_str()); + if (!wlst[ns - 1]) + return -1; + } + } + prev = sp + 1; + sp = candidate.find(' ', prev); + } + } + r++; // search for the next letter + } + } + return ns; +} + +// perhaps we doubled two characters (pattern aba -> ababa, for example vacation +// -> vacacation) +int SuggestMgr::doubletwochars(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + int state = 0; + int wl = strlen(word); + if (wl < 5 || !pAMgr) + return ns; + for (int i = 2; i < wl; i++) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3) { + std::string candidate(word, word + i - 1); + candidate.insert(candidate.end(), word + i + 1, word + wl); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + state = 0; + } + } else { + state = 0; + } + } + return ns; +} + +// perhaps we doubled two characters (pattern aba -> ababa, for example vacation +// -> vacacation) +int SuggestMgr::doubletwochars_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + int state = 0; + if (wl < 5 || !pAMgr) + return ns; + for (int i = 2; i < wl; i++) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3) { + std::vector<w_char> candidate_utf(word, word + i - 1); + candidate_utf.insert(candidate_utf.end(), word + i + 1, word + wl); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + state = 0; + } + } else { + state = 0; + } + } + return ns; +} + +// error is wrong char in place of correct one (case and keyboard related +// version) +int SuggestMgr::badcharkey(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + + // swap out each char one by one and try uppercase and neighbor + // keyboard chars in its place to see if that makes a good word + for (size_t i = 0; i < candidate.size(); ++i) { + char tmpc = candidate[i]; + // check with uppercase letters + candidate[i] = csconv[((unsigned char)tmpc)].cupper; + if (tmpc != candidate[i]) { + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate[i] = tmpc; + } + // check neighbor characters in keyboard string + if (!ckey) + continue; + char* loc = strchr(ckey, tmpc); + while (loc) { + if ((loc > ckey) && (*(loc - 1) != '|')) { + candidate[i] = *(loc - 1); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + if ((*(loc + 1) != '|') && (*(loc + 1) != '\0')) { + candidate[i] = *(loc + 1); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + loc = strchr(loc + 1, tmpc); + } + candidate[i] = tmpc; + } + return ns; +} + +// error is wrong char in place of correct one (case and keyboard related +// version) +int SuggestMgr::badcharkey_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::string candidate; + std::vector<w_char> candidate_utf(word, word + wl); + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int i = 0; i < wl; i++) { + w_char tmpc = candidate_utf[i]; + // check with uppercase letters + candidate_utf[i] = upper_utf(candidate_utf[i], 1); + if (tmpc != candidate_utf[i]) { + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + candidate_utf[i] = tmpc; + } + // check neighbor characters in keyboard string + if (!ckey) + continue; + w_char* loc = ckey_utf; + while ((loc < (ckey_utf + ckeyl)) && *loc != tmpc) + loc++; + while (loc < (ckey_utf + ckeyl)) { + if ((loc > ckey_utf) && *(loc - 1) != W_VLINE) { + candidate_utf[i] = *(loc - 1); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + if (((loc + 1) < (ckey_utf + ckeyl)) && (*(loc + 1) != W_VLINE)) { + candidate_utf[i] = *(loc + 1); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + do { + loc++; + } while ((loc < (ckey_utf + ckeyl)) && *loc != tmpc); + } + candidate_utf[i] = tmpc; + } + return ns; +} + +// error is wrong char in place of correct one +int SuggestMgr::badchar(char** wlst, const char* word, int ns, int cpdsuggest) { + std::string candidate(word); + clock_t timelimit = clock(); + int timer = MINTIMER; + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int j = 0; j < ctryl; j++) { + for (std::string::reverse_iterator aI = candidate.rbegin(), aEnd = candidate.rend(); aI != aEnd; ++aI) { + char tmpc = *aI; + if (ctry[j] == tmpc) + continue; + *aI = ctry[j]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + *aI = tmpc; + } + } + return ns; +} + +// error is wrong char in place of correct one +int SuggestMgr::badchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + std::string candidate; + clock_t timelimit = clock(); + int timer = MINTIMER; + // swap out each char one by one and try all the tryme + // chars in its place to see if that makes a good word + for (int j = 0; j < ctryl; j++) { + for (int i = wl - 1; i >= 0; i--) { + w_char tmpc = candidate_utf[i]; + if (tmpc == ctry_utf[j]) + continue; + candidate_utf[i] = ctry_utf[j]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, + &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate_utf[i] = tmpc; + } + } + return ns; +} + +// error is word has an extra letter it does not need +int SuggestMgr::extrachar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + // try omitting one char of word at a time + for (size_t i = 0; i < candidate_utf.size(); ++i) { + size_t index = candidate_utf.size() - 1 - i; + w_char tmpc = candidate_utf[index]; + candidate_utf.erase(candidate_utf.begin() + index); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate_utf.insert(candidate_utf.begin() + index, tmpc); + } + return ns; +} + +// error is word has an extra letter it does not need +int SuggestMgr::extrachar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + // try omitting one char of word at a time + for (size_t i = 0; i < candidate.size(); ++i) { + size_t index = candidate.size() - 1 - i; + char tmpc = candidate[index]; + candidate.erase(candidate.begin() + index); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + candidate.insert(candidate.begin() + index, tmpc); + } + return ns; +} + +// error is missing a letter it needs +int SuggestMgr::forgotchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + clock_t timelimit = clock(); + int timer = MINTIMER; + + // try inserting a tryme character before every letter (and the null + // terminator) + for (int k = 0; k < ctryl; ++k) { + for (size_t i = 0; i <= candidate.size(); ++i) { + size_t index = candidate.size() - i; + candidate.insert(candidate.begin() + index, ctry[k]); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate.erase(candidate.begin() + index); + } + } + return ns; +} + +// error is missing a letter it needs +int SuggestMgr::forgotchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + clock_t timelimit = clock(); + int timer = MINTIMER; + + // try inserting a tryme character at the end of the word and before every + // letter + for (int k = 0; k < ctryl; ++k) { + for (size_t i = 0; i <= candidate_utf.size(); ++i) { + size_t index = candidate_utf.size() - i; + candidate_utf.insert(candidate_utf.begin() + index, ctry_utf[k]); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, &timer, + &timelimit); + if (ns == -1) + return -1; + if (!timer) + return ns; + candidate_utf.erase(candidate_utf.begin() + index); + } + } + return ns; +} + +/* error is should have been two words */ +int SuggestMgr::twowords(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + int c1, c2; + int forbidden = 0; + int cwrd; + + int wl = strlen(word); + if (wl < 3) + return ns; + + if (langnum == LANG_hu) + forbidden = check_forbidden(word, wl); + + char* candidate = (char*)malloc(wl + 2); + strcpy(candidate + 1, word); + + // split the string into two pieces after every char + // if both pieces are good words make them a suggestion + for (char* p = candidate + 1; p[1] != '\0'; p++) { + p[-1] = *p; + // go to end of the UTF-8 character + while (utf8 && ((p[1] & 0xc0) == 0x80)) { + *p = p[1]; + p++; + } + if (utf8 && p[1] == '\0') + break; // last UTF-8 character + *p = '\0'; + c1 = checkword(candidate, strlen(candidate), cpdsuggest, NULL, NULL); + if (c1) { + c2 = checkword((p + 1), strlen(p + 1), cpdsuggest, NULL, NULL); + if (c2) { + *p = ' '; + + // spec. Hungarian code (need a better compound word support) + if ((langnum == LANG_hu) && !forbidden && + // if 3 repeating letter, use - instead of space + (((p[-1] == p[1]) && + (((p > candidate + 1) && (p[-1] == p[-2])) || (p[-1] == p[2]))) || + // or multiple compounding, with more, than 6 syllables + ((c1 == 3) && (c2 >= 2)))) + *p = '-'; + + cwrd = 1; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if (ns < maxSug) { + if (cwrd) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + free(candidate); + return -1; + } + ns++; + } + } else { + free(candidate); + return ns; + } + // add two word suggestion with dash, if TRY string contains + // "a" or "-" + // NOTE: cwrd doesn't modified for REP twoword sugg. + if (ctry && (strchr(ctry, 'a') || strchr(ctry, '-')) && + mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) { + *p = '-'; + for (int k = 0; k < ns; k++) { + if (strcmp(candidate, wlst[k]) == 0) { + cwrd = 0; + break; + } + } + if (ns < maxSug) { + if (cwrd) { + wlst[ns] = mystrdup(candidate); + if (wlst[ns] == NULL) { + free(candidate); + return -1; + } + ns++; + } + } else { + free(candidate); + return ns; + } + } + } + } + } + free(candidate); + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + + // try swapping adjacent chars one by one + for (size_t i = 0; i < candidate.size() - 1; ++i) { + std::swap(candidate[i], candidate[i+1]); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(candidate[i], candidate[i+1]); + } + + // try double swaps for short words + // ahev -> have, owudl -> would + if (candidate.size() == 4 || candidate.size() == 5) { + candidate[0] = word[1]; + candidate[1] = word[0]; + candidate[2] = word[2]; + candidate[candidate.size() - 2] = word[candidate.size() - 1]; + candidate[candidate.size() - 1] = word[candidate.size() - 2]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + if (candidate.size() == 5) { + candidate[0] = word[0]; + candidate[1] = word[2]; + candidate[2] = word[1]; + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + } + + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + + std::string candidate; + // try swapping adjacent chars one by one + for (size_t i = 0; i < candidate_utf.size() - 1; ++i) { + std::swap(candidate_utf[i], candidate_utf[i+1]); + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(candidate_utf[i], candidate_utf[i+1]); + } + + // try double swaps for short words + // ahev -> have, owudl -> would, suodn -> sound + if (candidate_utf.size() == 4 || candidate_utf.size() == 5) { + candidate_utf[0] = word[1]; + candidate_utf[1] = word[0]; + candidate_utf[2] = word[2]; + candidate_utf[candidate_utf.size() - 2] = word[candidate_utf.size() - 1]; + candidate_utf[candidate_utf.size() - 1] = word[candidate_utf.size() - 2]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + if (candidate_utf.size() == 5) { + candidate_utf[0] = word[0]; + candidate_utf[1] = word[2]; + candidate_utf[2] = word[1]; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + } + return ns; +} + +// error is not adjacent letter were swapped +int SuggestMgr::longswapchar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + // try swapping not adjacent chars one by one + for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { + for (std::string::iterator q = candidate.begin(); q < candidate.end(); ++q) { + if (abs(std::distance(q, p)) > 1) { + std::swap(*p, *q); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + std::swap(*p, *q); + } + } + } + return ns; +} + +// error is adjacent letter were swapped +int SuggestMgr::longswapchar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + // try swapping not adjacent chars + for (std::vector<w_char>::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (std::vector<w_char>::iterator q = candidate_utf.begin(); q < candidate_utf.end(); ++q) { + if (abs(std::distance(q, p)) > 1) { + std::swap(*p, *q); + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + std::swap(*p, *q); + } + } + } + return ns; +} + +// error is a letter was moved +int SuggestMgr::movechar(char** wlst, + const char* word, + int ns, + int cpdsuggest) { + std::string candidate(word); + if (candidate.size() < 2) + return ns; + + // try moving a char + for (std::string::iterator p = candidate.begin(); p < candidate.end(); ++p) { + for (std::string::iterator q = p + 1; q < candidate.end() && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate.size(), candidate.begin()); + } + + for (std::string::reverse_iterator p = candidate.rbegin(), pEnd = candidate.rend() - 1; p != pEnd; ++p) { + for (std::string::reverse_iterator q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate.size(), candidate.begin()); + } + + return ns; +} + +// error is a letter was moved +int SuggestMgr::movechar_utf(char** wlst, + const w_char* word, + int wl, + int ns, + int cpdsuggest) { + std::vector<w_char> candidate_utf(word, word + wl); + if (candidate_utf.size() < 2) + return ns; + + // try moving a char + for (std::vector<w_char>::iterator p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (std::vector<w_char>::iterator q = p + 1; q < candidate_utf.end() && std::distance(p, q) < 10; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); + } + + for (std::vector<w_char>::iterator p = candidate_utf.begin() + candidate_utf.size() - 1; p > candidate_utf.begin(); --p) { + for (std::vector<w_char>::iterator q = p - 1; q >= candidate_utf.begin() && std::distance(q, p) < 10; --q) { + std::swap(*q, *(q + 1)); + if (std::distance(q, p) < 2) + continue; // omit swap char + std::string candidate; + u16_u8(candidate, candidate_utf); + ns = testsug(wlst, candidate.c_str(), candidate.size(), ns, cpdsuggest, NULL, + NULL); + if (ns == -1) + return -1; + } + std::copy(word, word + candidate_utf.size(), candidate_utf.begin()); + } + + return ns; +} + +// generate a set of suggestions for very poorly spelled words +int SuggestMgr::ngsuggest(char** wlst, + const char* w, + int ns, + HashMgr** pHMgr, + int md) { + int i, j; + int lval; + int sc; + int lp, lpphon; + int nonbmp = 0; + + // exhaustively search through all root words + // keeping track of the MAX_ROOTS most similar root words + struct hentry* roots[MAX_ROOTS]; + char* rootsphon[MAX_ROOTS]; + int scores[MAX_ROOTS]; + int scoresphon[MAX_ROOTS]; + for (i = 0; i < MAX_ROOTS; i++) { + roots[i] = NULL; + scores[i] = -100 * i; + rootsphon[i] = NULL; + scoresphon[i] = -100 * i; + } + lp = MAX_ROOTS - 1; + lpphon = MAX_ROOTS - 1; + int low = NGRAM_LOWERING; + + std::string w2; + const char* word = w; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + std::vector<w_char> u8; + int nc = strlen(word); + int n = (utf8) ? u8_u16(u8, word) : nc; + + // set character based ngram suggestion for words with non-BMP Unicode + // characters + if (n == -1) { + utf8 = 0; // XXX not state-free + n = nc; + nonbmp = 1; + low = 0; + } + + struct hentry* hp = NULL; + int col = -1; + phonetable* ph = (pAMgr) ? pAMgr->get_phonetable() : NULL; + std::string target; + std::string candidate; + if (ph) { + if (utf8) { + std::vector<w_char> _w; + u8_u16(_w, word); + mkallcap_utf(_w, langnum); + u16_u8(candidate, _w); + } else { + candidate.assign(word); + if (!nonbmp) + mkallcap(candidate, csconv); + } + target = phonet(candidate, *ph); // XXX phonet() is 8-bit (nc, not n) + } + + FLAG forbiddenword = pAMgr ? pAMgr->get_forbiddenword() : FLAG_NULL; + FLAG nosuggest = pAMgr ? pAMgr->get_nosuggest() : FLAG_NULL; + FLAG nongramsuggest = pAMgr ? pAMgr->get_nongramsuggest() : FLAG_NULL; + FLAG onlyincompound = pAMgr ? pAMgr->get_onlyincompound() : FLAG_NULL; + + for (i = 0; i < md; i++) { + while (0 != (hp = (pHMgr[i])->walk_hashtable(col, hp))) { + if ((hp->astr) && (pAMgr) && + (TESTAFF(hp->astr, forbiddenword, hp->alen) || + TESTAFF(hp->astr, ONLYUPCASEFLAG, hp->alen) || + TESTAFF(hp->astr, nosuggest, hp->alen) || + TESTAFF(hp->astr, nongramsuggest, hp->alen) || + TESTAFF(hp->astr, onlyincompound, hp->alen))) + continue; + + sc = ngram(3, word, HENTRY_WORD(hp), NGRAM_LONGER_WORSE + low) + + leftcommonsubstring(word, HENTRY_WORD(hp)); + + // check special pronounciation + std::string f; + if ((hp->var & H_OPT_PHON) && + copy_field(f, HENTRY_DATA(hp), MORPH_PHON)) { + int sc2 = ngram(3, word, f, NGRAM_LONGER_WORSE + low) + + +leftcommonsubstring(word, f.c_str()); + if (sc2 > sc) + sc = sc2; + } + + int scphon = -20000; + if (ph && (sc > 2) && (abs(n - (int)hp->clen) <= 3)) { + if (utf8) { + std::vector<w_char> _w; + u8_u16(_w, HENTRY_WORD(hp)); + mkallcap_utf(_w, langnum); + u16_u8(candidate, _w); + } else { + candidate.assign(HENTRY_WORD(hp)); + mkallcap(candidate, csconv); + } + std::string target2 = phonet(candidate, *ph); + scphon = 2 * ngram(3, target, target2, NGRAM_LONGER_WORSE); + } + + if (sc > scores[lp]) { + scores[lp] = sc; + roots[lp] = hp; + lval = sc; + for (j = 0; j < MAX_ROOTS; j++) + if (scores[j] < lval) { + lp = j; + lval = scores[j]; + } + } + + if (scphon > scoresphon[lpphon]) { + scoresphon[lpphon] = scphon; + rootsphon[lpphon] = HENTRY_WORD(hp); + lval = scphon; + for (j = 0; j < MAX_ROOTS; j++) + if (scoresphon[j] < lval) { + lpphon = j; + lval = scoresphon[j]; + } + } + } + } + + // find minimum threshold for a passable suggestion + // mangle original word three differnt ways + // and score them to generate a minimum acceptable score + int thresh = 0; + for (int sp = 1; sp < 4; sp++) { + if (utf8) { + for (int k = sp; k < n; k += 4) { + u8[k].l = '*'; + u8[k].h = 0; + } + std::string mw; + u16_u8(mw, u8); + thresh = thresh + ngram(n, word, mw, NGRAM_ANY_MISMATCH + low); + } else { + std::string mw(word); + for (int k = sp; k < n; k += 4) + mw[k] = '*'; + thresh = thresh + ngram(n, word, mw, NGRAM_ANY_MISMATCH + low); + } + } + thresh = thresh / 3; + thresh--; + + // now expand affixes on each of these root words and + // and use length adjusted ngram scores to select + // possible suggestions + char* guess[MAX_GUESS]; + char* guessorig[MAX_GUESS]; + int gscore[MAX_GUESS]; + for (i = 0; i < MAX_GUESS; i++) { + guess[i] = NULL; + guessorig[i] = NULL; + gscore[i] = -100 * i; + } + + lp = MAX_GUESS - 1; + + struct guessword* glst; + glst = (struct guessword*)calloc(MAX_WORDS, sizeof(struct guessword)); + if (!glst) { + if (nonbmp) + utf8 = 1; + return ns; + } + + for (i = 0; i < MAX_ROOTS; i++) { + if (roots[i]) { + struct hentry* rp = roots[i]; + + std::string f; + const char *field = NULL; + if ((rp->var & H_OPT_PHON) && copy_field(f, HENTRY_DATA(rp), MORPH_PHON)) + field = f.c_str(); + int nw = pAMgr->expand_rootword( + glst, MAX_WORDS, HENTRY_WORD(rp), rp->blen, rp->astr, rp->alen, word, + nc, field); + + for (int k = 0; k < nw; k++) { + sc = ngram(n, word, glst[k].word, NGRAM_ANY_MISMATCH + low) + + leftcommonsubstring(word, glst[k].word); + + if (sc > thresh) { + if (sc > gscore[lp]) { + if (guess[lp]) { + free(guess[lp]); + if (guessorig[lp]) { + free(guessorig[lp]); + guessorig[lp] = NULL; + } + } + gscore[lp] = sc; + guess[lp] = glst[k].word; + guessorig[lp] = glst[k].orig; + lval = sc; + for (j = 0; j < MAX_GUESS; j++) + if (gscore[j] < lval) { + lp = j; + lval = gscore[j]; + } + } else { + free(glst[k].word); + if (glst[k].orig) + free(glst[k].orig); + } + } else { + free(glst[k].word); + if (glst[k].orig) + free(glst[k].orig); + } + } + } + } + free(glst); + + // now we are done generating guesses + // sort in order of decreasing score + + bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); + if (ph) + bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); + + // weight suggestions with a similarity index, based on + // the longest common subsequent algorithm and resort + + int is_swap = 0; + int re = 0; + double fact = 1.0; + if (pAMgr) { + int maxd = pAMgr->get_maxdiff(); + if (maxd >= 0) + fact = (10.0 - maxd) / 5.0; + } + + for (i = 0; i < MAX_GUESS; i++) { + if (guess[i]) { + // lowering guess[i] + std::string gl; + int len; + if (utf8) { + std::vector<w_char> _w; + len = u8_u16(_w, guess[i]); + mkallsmall_utf(_w, langnum); + u16_u8(gl, _w); + } else { + gl.assign(guess[i]); + if (!nonbmp) + mkallsmall(gl, csconv); + len = strlen(guess[i]); + } + + int _lcs = lcslen(word, gl.c_str()); + + // same characters with different casing + if ((n == len) && (n == _lcs)) { + gscore[i] += 2000; + break; + } + // using 2-gram instead of 3, and other weightening + + re = ngram(2, word, gl, NGRAM_ANY_MISMATCH + low + NGRAM_WEIGHTED) + + ngram(2, gl, word, NGRAM_ANY_MISMATCH + low + NGRAM_WEIGHTED); + + gscore[i] = + // length of longest common subsequent minus length difference + 2 * _lcs - abs((int)(n - len)) + + // weight length of the left common substring + leftcommonsubstring(word, gl.c_str()) + + // weight equal character positions + (!nonbmp && commoncharacterpositions(word, gl.c_str(), &is_swap) + ? 1 + : 0) + + // swap character (not neighboring) + ((is_swap) ? 10 : 0) + + // ngram + ngram(4, word, gl, NGRAM_ANY_MISMATCH + low) + + // weighted ngrams + re + + // different limit for dictionaries with PHONE rules + (ph ? (re < len * fact ? -1000 : 0) + : (re < (n + len) * fact ? -1000 : 0)); + } + } + + bubblesort(&guess[0], &guessorig[0], &gscore[0], MAX_GUESS); + + // phonetic version + if (ph) + for (i = 0; i < MAX_ROOTS; i++) { + if (rootsphon[i]) { + // lowering rootphon[i] + std::string gl; + int len; + if (utf8) { + std::vector<w_char> _w; + len = u8_u16(_w, rootsphon[i]); + mkallsmall_utf(_w, langnum); + u16_u8(gl, _w); + } else { + gl.assign(rootsphon[i]); + if (!nonbmp) + mkallsmall(gl, csconv); + len = strlen(rootsphon[i]); + } + + // heuristic weigthing of ngram scores + scoresphon[i] += 2 * lcslen(word, gl) - abs((int)(n - len)) + + // weight length of the left common substring + leftcommonsubstring(word, gl.c_str()); + } + } + + if (ph) + bubblesort(&rootsphon[0], NULL, &scoresphon[0], MAX_ROOTS); + + // copy over + int oldns = ns; + + int same = 0; + for (i = 0; i < MAX_GUESS; i++) { + if (guess[i]) { + if ((ns < oldns + maxngramsugs) && (ns < maxSug) && + (!same || (gscore[i] > 1000))) { + int unique = 1; + // leave only excellent suggestions, if exists + if (gscore[i] > 1000) + same = 1; + else if (gscore[i] < -100) { + same = 1; + // keep the best ngram suggestions, unless in ONLYMAXDIFF mode + if (ns > oldns || (pAMgr && pAMgr->get_onlymaxdiff())) { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + continue; + } + } + for (j = 0; j < ns; j++) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if ((!guessorig[i] && strstr(guess[i], wlst[j])) || + (guessorig[i] && strstr(guessorig[i], wlst[j])) || + // check forbidden words + !checkword(guess[i], strlen(guess[i]), 0, NULL, NULL)) { + unique = 0; + break; + } + } + if (unique) { + wlst[ns++] = guess[i]; + if (guessorig[i]) { + free(guess[i]); + wlst[ns - 1] = guessorig[i]; + } + } else { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + } + } else { + free(guess[i]); + if (guessorig[i]) + free(guessorig[i]); + } + } + } + + oldns = ns; + if (ph) + for (i = 0; i < MAX_ROOTS; i++) { + if (rootsphon[i]) { + if ((ns < oldns + MAXPHONSUGS) && (ns < maxSug)) { + int unique = 1; + for (j = 0; j < ns; j++) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if (strstr(rootsphon[i], wlst[j]) || + // check forbidden words + !checkword(rootsphon[i], strlen(rootsphon[i]), 0, NULL, NULL)) { + unique = 0; + break; + } + } + if (unique) { + wlst[ns++] = mystrdup(rootsphon[i]); + if (!wlst[ns - 1]) + return ns - 1; + } + } + } + } + + if (nonbmp) + utf8 = 1; + return ns; +} + +// see if a candidate suggestion is spelled correctly +// needs to check both root words and words with affixes + +// obsolote MySpell-HU modifications: +// return value 2 and 3 marks compounding with hyphen (-) +// `3' marks roots without suffix +int SuggestMgr::checkword(const char* word, + int len, + int cpdsuggest, + int* timer, + clock_t* timelimit) { + struct hentry* rv = NULL; + struct hentry* rv2 = NULL; + int nosuffix = 0; + + // check time limit + if (timer) { + (*timer)--; + if (!(*timer) && timelimit) { + if ((clock() - *timelimit) > TIMELIMIT) + return 0; + *timer = MAXPLUSTIMER; + } + } + + if (pAMgr) { + if (cpdsuggest == 1) { + if (pAMgr->get_compound()) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + rv = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 1, + 0); // EXT + if (rv && + (!(rv2 = pAMgr->lookup(word)) || !rv2->astr || + !(TESTAFF(rv2->astr, pAMgr->get_forbiddenword(), rv2->alen) || + TESTAFF(rv2->astr, pAMgr->get_nosuggest(), rv2->alen)))) + return 3; // XXX obsolote categorisation + only ICONV needs affix + // flag check? + } + return 0; + } + + rv = pAMgr->lookup(word); + + if (rv) { + if ((rv->astr) && + (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen))) + return 0; + while (rv) { + if (rv->astr && + (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { + rv = rv->next_homonym; + } else + break; + } + } else + rv = pAMgr->prefix_check(word, len, + 0); // only prefix, and prefix + suffix XXX + + if (rv) { + nosuffix = 1; + } else { + rv = pAMgr->suffix_check(word, len, 0, NULL, NULL, 0, + NULL); // only suffix + } + + if (!rv && pAMgr->have_contclass()) { + rv = pAMgr->suffix_check_twosfx(word, len, 0, NULL, FLAG_NULL); + if (!rv) + rv = pAMgr->prefix_check_twosfx(word, len, 1, FLAG_NULL); + } + + // check forbidden words + if ((rv) && (rv->astr) && + (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) || + TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) + return 0; + + if (rv) { // XXX obsolote + if ((pAMgr->get_compoundflag()) && + TESTAFF(rv->astr, pAMgr->get_compoundflag(), rv->alen)) + return 2 + nosuffix; + return 1; + } + } + return 0; +} + +int SuggestMgr::check_forbidden(const char* word, int len) { + struct hentry* rv = NULL; + + if (pAMgr) { + rv = pAMgr->lookup(word); + if (rv && rv->astr && + (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) + rv = NULL; + if (!(pAMgr->prefix_check(word, len, 1))) + rv = pAMgr->suffix_check(word, len, 0, NULL, NULL, 0, + NULL); // prefix+suffix, suffix + // check forbidden words + if ((rv) && (rv->astr) && + TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen)) + return 1; + } + return 0; +} + +char* SuggestMgr::suggest_morph(const char* w) { + char result[MAXLNLEN]; + char* r = (char*)result; + char* st; + + struct hentry* rv = NULL; + + *result = '\0'; + + if (!pAMgr) + return NULL; + + std::string w2; + const char* word = w; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + } + + rv = pAMgr->lookup(word); + + while (rv) { + if ((!rv->astr) || + !(TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) { + if (!HENTRY_FIND(rv, MORPH_STEM)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, MORPH_STEM, MAXLNLEN); + mystrcat(result, word, MAXLNLEN); + } + if (HENTRY_DATA(rv)) { + mystrcat(result, " ", MAXLNLEN); + mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN); + } + mystrcat(result, "\n", MAXLNLEN); + } + rv = rv->next_homonym; + } + + st = pAMgr->affix_check_morph(word, strlen(word)); + if (st) { + mystrcat(result, st, MAXLNLEN); + free(st); + } + + if (pAMgr->get_compound() && (*result == '\0')) { + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + pAMgr->compound_check_morph(word, strlen(word), 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, &r, + NULL); + } + + return (*result) ? mystrdup(line_uniq(result, MSEP_REC)) : NULL; +} + +/* affixation */ +char* SuggestMgr::suggest_hentry_gen(hentry* rv, const char* pattern) { + char result[MAXLNLEN]; + *result = '\0'; + int sfxcount = get_sfxcount(pattern); + + if (get_sfxcount(HENTRY_DATA(rv)) > sfxcount) + return NULL; + + if (HENTRY_DATA(rv)) { + char* aff = pAMgr->morphgen(HENTRY_WORD(rv), rv->blen, rv->astr, rv->alen, + HENTRY_DATA(rv), pattern, 0); + if (aff) { + mystrcat(result, aff, MAXLNLEN); + mystrcat(result, "\n", MAXLNLEN); + free(aff); + } + } + + // check all allomorphs + char allomorph[MAXLNLEN]; + char* p = NULL; + if (HENTRY_DATA(rv)) + p = (char*)strstr(HENTRY_DATA2(rv), MORPH_ALLOMORPH); + while (p) { + struct hentry* rv2 = NULL; + p += MORPH_TAG_LEN; + int plen = fieldlen(p); + strncpy(allomorph, p, plen); + allomorph[plen] = '\0'; + rv2 = pAMgr->lookup(allomorph); + while (rv2) { + // if (HENTRY_DATA(rv2) && get_sfxcount(HENTRY_DATA(rv2)) <= + // sfxcount) { + if (HENTRY_DATA(rv2)) { + char* st = (char*)strstr(HENTRY_DATA2(rv2), MORPH_STEM); + if (st && (strncmp(st + MORPH_TAG_LEN, HENTRY_WORD(rv), + fieldlen(st + MORPH_TAG_LEN)) == 0)) { + char* aff = pAMgr->morphgen(HENTRY_WORD(rv2), rv2->blen, rv2->astr, + rv2->alen, HENTRY_DATA(rv2), pattern, 0); + if (aff) { + mystrcat(result, aff, MAXLNLEN); + mystrcat(result, "\n", MAXLNLEN); + free(aff); + } + } + } + rv2 = rv2->next_homonym; + } + p = strstr(p + plen, MORPH_ALLOMORPH); + } + + return (*result) ? mystrdup(result) : NULL; +} + +char* SuggestMgr::suggest_gen(char** desc, int n, const char* pattern) { + if (n == 0 || !pAMgr) + return NULL; + + std::string result2; + std::string newpattern; + struct hentry* rv = NULL; + + // search affixed forms with and without derivational suffixes + while (1) { + for (int k = 0; k < n; k++) { + std::string result; + + // add compound word parts (except the last one) + char* s = (char*)desc[k]; + char* part = strstr(s, MORPH_PART); + if (part) { + char* nextpart = strstr(part + 1, MORPH_PART); + while (nextpart) { + std::string field; + copy_field(field, part, MORPH_PART); + result.append(field); + part = nextpart; + nextpart = strstr(part + 1, MORPH_PART); + } + s = part; + } + + char** pl; + std::string tok(s); + size_t pos = tok.find(" | "); + while (pos != std::string::npos) { + tok[pos + 1] = MSEP_ALT; + pos = tok.find(" | ", pos); + } + int pln = line_tok(tok.c_str(), &pl, MSEP_ALT); + for (int i = 0; i < pln; i++) { + // remove inflectional and terminal suffixes + char* is = strstr(pl[i], MORPH_INFL_SFX); + if (is) + *is = '\0'; + char* ts = strstr(pl[i], MORPH_TERM_SFX); + while (ts) { + *ts = '_'; + ts = strstr(pl[i], MORPH_TERM_SFX); + } + char* st = strstr(s, MORPH_STEM); + if (st) { + copy_field(tok, st, MORPH_STEM); + rv = pAMgr->lookup(tok.c_str()); + while (rv) { + std::string newpat(pl[i]); + newpat.append(pattern); + char* sg = suggest_hentry_gen(rv, newpat.c_str()); + if (!sg) + sg = suggest_hentry_gen(rv, pattern); + if (sg) { + char** gen; + int genl = line_tok(sg, &gen, MSEP_REC); + free(sg); + sg = NULL; + for (int j = 0; j < genl; j++) { + result2.push_back(MSEP_REC); + result2.append(result); + if (strstr(pl[i], MORPH_SURF_PFX)) { + std::string field; + copy_field(field, pl[i], MORPH_SURF_PFX); + result2.append(field); + } + result2.append(gen[j]); + } + freelist(&gen, genl); + } + rv = rv->next_homonym; + } + } + } + freelist(&pl, pln); + } + + if (!result2.empty() || !strstr(pattern, MORPH_DERI_SFX)) + break; + + newpattern.assign(pattern); + mystrrep(newpattern, MORPH_DERI_SFX, MORPH_TERM_SFX); + pattern = newpattern.c_str(); + } + return (!result2.empty() ? mystrdup(result2.c_str()) : NULL); +} + +// generate an n-gram score comparing s1 and s2 +int SuggestMgr::ngram(int n, + const std::string& s1, + const std::string& s2, + int opt) { + int nscore = 0; + int ns; + int l1; + int l2; + int test = 0; + + if (utf8) { + std::vector<w_char> su1; + std::vector<w_char> su2; + l1 = u8_u16(su1, s1); + l2 = u8_u16(su2, s2); + if ((l2 <= 0) || (l1 == -1)) + return 0; + // lowering dictionary word + if (opt & NGRAM_LOWERING) + mkallsmall_utf(su2, langnum); + for (int j = 1; j <= n; j++) { + ns = 0; + for (int i = 0; i <= (l1 - j); i++) { + int k = 0; + for (int l = 0; l <= (l2 - j); l++) { + for (k = 0; k < j; k++) { + w_char& c1 = su1[i + k]; + w_char& c2 = su2[l + k]; + if ((c1.l != c2.l) || (c1.h != c2.h)) + break; + } + if (k == j) { + ns++; + break; + } + } + if (k != j && opt & NGRAM_WEIGHTED) { + ns--; + test++; + if (i == 0 || i == l1 - j) + ns--; // side weight + } + } + nscore = nscore + ns; + if (ns < 2 && !(opt & NGRAM_WEIGHTED)) + break; + } + } else { + l2 = s2.size(); + if (l2 == 0) + return 0; + l1 = s1.size(); + std::string t(s2); + if (opt & NGRAM_LOWERING) + mkallsmall(t, csconv); + for (int j = 1; j <= n; j++) { + ns = 0; + for (int i = 0; i <= (l1 - j); i++) { + std::string temp(s1.substr(i, j)); + if (t.find(temp) != std::string::npos) { + ns++; + } else if (opt & NGRAM_WEIGHTED) { + ns--; + test++; + if (i == 0 || i == l1 - j) + ns--; // side weight + } + } + nscore = nscore + ns; + if (ns < 2 && !(opt & NGRAM_WEIGHTED)) + break; + } + } + + ns = 0; + if (opt & NGRAM_LONGER_WORSE) + ns = (l2 - l1) - 2; + if (opt & NGRAM_ANY_MISMATCH) + ns = abs(l2 - l1) - 2; + ns = (nscore - ((ns > 0) ? ns : 0)); + return ns; +} + +// length of the left common substring of s1 and (decapitalised) s2 +int SuggestMgr::leftcommonsubstring(const char* s1, const char* s2) { + if (utf8) { + std::vector<w_char> su1; + std::vector<w_char> su2; + int l1 = u8_u16(su1, s1); + int l2 = u8_u16(su2, s2); + // decapitalize dictionary word + if (complexprefixes) { + if (su1[l1 - 1] == su2[l2 - 1]) + return 1; + } else { + unsigned short idx = su2.empty() ? 0 : (su2[0].h << 8) + su2[0].l; + unsigned short otheridx = su1.empty() ? 0 : (su1[0].h << 8) + su1[0].l; + if (otheridx != idx && (otheridx != unicodetolower(idx, langnum))) + return 0; + int i; + for (i = 1; (i < l1) && (i < l2) && (su1[i].l == su2[i].l) && + (su1[i].h == su2[i].h); + i++) + ; + return i; + } + } else { + if (complexprefixes) { + int l1 = strlen(s1); + int l2 = strlen(s2); + if (l1 <= l2 && s2[l1 - 1] == s2[l2 - 1]) + return 1; + } else if (csconv) { + const char* olds = s1; + // decapitalise dictionary word + if ((*s1 != *s2) && (*s1 != csconv[((unsigned char)*s2)].clower)) + return 0; + do { + s1++; + s2++; + } while ((*s1 == *s2) && (*s1 != '\0')); + return (int)(s1 - olds); + } + } + return 0; +} + +int SuggestMgr::commoncharacterpositions(const char* s1, + const char* s2, + int* is_swap) { + int num = 0; + int diff = 0; + int diffpos[2]; + *is_swap = 0; + if (utf8) { + std::vector<w_char> su1; + std::vector<w_char> su2; + int l1 = u8_u16(su1, s1); + int l2 = u8_u16(su2, s2); + + if (l1 <= 0 || l2 <= 0) + return 0; + + // decapitalize dictionary word + if (complexprefixes) { + su2[l2 - 1] = lower_utf(su2[l2 - 1], langnum); + } else { + su2[0] = lower_utf(su2[0], langnum); + } + for (int i = 0; (i < l1) && (i < l2); i++) { + if (su1[i] == su2[i]) { + num++; + } else { + if (diff < 2) + diffpos[diff] = i; + diff++; + } + } + if ((diff == 2) && (l1 == l2) && + (su1[diffpos[0]] == su2[diffpos[1]]) && + (su1[diffpos[1]] == su2[diffpos[0]])) + *is_swap = 1; + } else { + size_t i; + std::string t(s2); + // decapitalize dictionary word + if (complexprefixes) { + size_t l2 = t.size(); + t[l2 - 1] = csconv[(unsigned char)t[l2 - 1]].clower; + } else { + mkallsmall(t, csconv); + } + for (i = 0; (*(s1 + i) != 0) && i < t.size(); i++) { + if (*(s1 + i) == t[i]) { + num++; + } else { + if (diff < 2) + diffpos[diff] = i; + diff++; + } + } + if ((diff == 2) && (*(s1 + i) == 0) && i == t.size() && + (*(s1 + diffpos[0]) == t[diffpos[1]]) && + (*(s1 + diffpos[1]) == t[diffpos[0]])) + *is_swap = 1; + } + return num; +} + +int SuggestMgr::mystrlen(const char* word) { + if (utf8) { + std::vector<w_char> w; + return u8_u16(w, word); + } else + return strlen(word); +} + +// sort in decreasing order of score +void SuggestMgr::bubblesort(char** rword, char** rword2, int* rsc, int n) { + int m = 1; + while (m < n) { + int j = m; + while (j > 0) { + if (rsc[j - 1] < rsc[j]) { + int sctmp = rsc[j - 1]; + char* wdtmp = rword[j - 1]; + rsc[j - 1] = rsc[j]; + rword[j - 1] = rword[j]; + rsc[j] = sctmp; + rword[j] = wdtmp; + if (rword2) { + wdtmp = rword2[j - 1]; + rword2[j - 1] = rword2[j]; + rword2[j] = wdtmp; + } + j--; + } else + break; + } + m++; + } + return; +} + +// longest common subsequence +void SuggestMgr::lcs(const char* s, + const char* s2, + int* l1, + int* l2, + char** result) { + int n, m; + std::vector<w_char> su; + std::vector<w_char> su2; + char* b; + char* c; + int i; + int j; + if (utf8) { + m = u8_u16(su, s); + n = u8_u16(su2, s2); + } else { + m = strlen(s); + n = strlen(s2); + } + c = (char*)malloc((m + 1) * (n + 1)); + b = (char*)malloc((m + 1) * (n + 1)); + if (!c || !b) { + if (c) + free(c); + if (b) + free(b); + *result = NULL; + return; + } + for (i = 1; i <= m; i++) + c[i * (n + 1)] = 0; + for (j = 0; j <= n; j++) + c[j] = 0; + for (i = 1; i <= m; i++) { + for (j = 1; j <= n; j++) { + if (((utf8) && (su[i - 1] == su2[j - 1])) || + ((!utf8) && (s[i - 1] == s2[j - 1]))) { + c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j - 1] + 1; + b[i * (n + 1) + j] = LCS_UPLEFT; + } else if (c[(i - 1) * (n + 1) + j] >= c[i * (n + 1) + j - 1]) { + c[i * (n + 1) + j] = c[(i - 1) * (n + 1) + j]; + b[i * (n + 1) + j] = LCS_UP; + } else { + c[i * (n + 1) + j] = c[i * (n + 1) + j - 1]; + b[i * (n + 1) + j] = LCS_LEFT; + } + } + } + *result = b; + free(c); + *l1 = m; + *l2 = n; +} + +int SuggestMgr::lcslen(const char* s, const char* s2) { + int m; + int n; + int i; + int j; + char* result; + int len = 0; + lcs(s, s2, &m, &n, &result); + if (!result) + return 0; + i = m; + j = n; + while ((i != 0) && (j != 0)) { + if (result[i * (n + 1) + j] == LCS_UPLEFT) { + len++; + i--; + j--; + } else if (result[i * (n + 1) + j] == LCS_UP) { + i--; + } else + j--; + } + free(result); + return len; +} + +int SuggestMgr::lcslen(const std::string& s, const std::string& s2) { + return lcslen(s.c_str(), s2.c_str()); +} diff --git a/extensions/spellcheck/hunspell/src/suggestmgr.hxx b/extensions/spellcheck/hunspell/src/suggestmgr.hxx new file mode 100644 index 000000000..675d98eb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/suggestmgr.hxx @@ -0,0 +1,198 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada + * And Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All modifications to the source code must be clearly marked as + * such. Binary redistributions based on modified source code + * must be clearly marked as modified versions in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SUGGESTMGR_HXX_ +#define _SUGGESTMGR_HXX_ + +#define MAX_ROOTS 100 +#define MAX_WORDS 100 +#define MAX_GUESS 200 +#define MAXNGRAMSUGS 4 +#define MAXPHONSUGS 2 +#define MAXCOMPOUNDSUGS 3 + +// timelimit: max ~1/4 sec (process time on Linux) for a time consuming function +#define TIMELIMIT (CLOCKS_PER_SEC >> 2) +#define MINTIMER 100 +#define MAXPLUSTIMER 100 + +#define NGRAM_LONGER_WORSE (1 << 0) +#define NGRAM_ANY_MISMATCH (1 << 1) +#define NGRAM_LOWERING (1 << 2) +#define NGRAM_WEIGHTED (1 << 3) + +#include "hunvisapi.h" + +#include "atypes.hxx" +#include "affixmgr.hxx" +#include "hashmgr.hxx" +#include "langnum.hxx" +#include <time.h> + +enum { LCS_UP, LCS_LEFT, LCS_UPLEFT }; + +class LIBHUNSPELL_DLL_EXPORTED SuggestMgr { + private: + SuggestMgr(const SuggestMgr&); + SuggestMgr& operator=(const SuggestMgr&); + + private: + char* ckey; + int ckeyl; + w_char* ckey_utf; + + char* ctry; + int ctryl; + w_char* ctry_utf; + + AffixMgr* pAMgr; + int maxSug; + struct cs_info* csconv; + int utf8; + int langnum; + int nosplitsugs; + int maxngramsugs; + int maxcpdsugs; + int complexprefixes; + + public: + SuggestMgr(const char* tryme, int maxn, AffixMgr* aptr); + ~SuggestMgr(); + + int suggest(char*** slst, const char* word, int nsug, int* onlycmpdsug); + int ngsuggest(char** wlst, const char* word, int ns, HashMgr** pHMgr, int md); + int suggest_auto(char*** slst, const char* word, int nsug); + int suggest_stems(char*** slst, const char* word, int nsug); + int suggest_pos_stems(char*** slst, const char* word, int nsug); + + char* suggest_morph(const char* word); + char* suggest_gen(char** pl, int pln, const char* pattern); + char* suggest_morph_for_spelling_error(const char* word); + + private: + int testsug(char** wlst, + const char* candidate, + int wl, + int ns, + int cpdsuggest, + int* timer, + clock_t* timelimit); + int checkword(const char*, int, int, int*, clock_t*); + int check_forbidden(const char*, int); + + int capchars(char**, const char*, int, int); + int replchars(char**, const char*, int, int); + int doubletwochars(char**, const char*, int, int); + int forgotchar(char**, const char*, int, int); + int swapchar(char**, const char*, int, int); + int longswapchar(char**, const char*, int, int); + int movechar(char**, const char*, int, int); + int extrachar(char**, const char*, int, int); + int badcharkey(char**, const char*, int, int); + int badchar(char**, const char*, int, int); + int twowords(char**, const char*, int, int); + int fixstems(char**, const char*, int); + + int capchars_utf(char**, const w_char*, int wl, int, int); + int doubletwochars_utf(char**, const w_char*, int wl, int, int); + int forgotchar_utf(char**, const w_char*, int wl, int, int); + int extrachar_utf(char**, const w_char*, int wl, int, int); + int badcharkey_utf(char**, const w_char*, int wl, int, int); + int badchar_utf(char**, const w_char*, int wl, int, int); + int swapchar_utf(char**, const w_char*, int wl, int, int); + int longswapchar_utf(char**, const w_char*, int, int, int); + int movechar_utf(char**, const w_char*, int, int, int); + + int mapchars(char**, const char*, int, int); + int map_related(const char*, + std::string&, + int, + char** wlst, + int, + int, + const mapentry*, + int, + int*, + clock_t*); + int ngram(int n, const std::string& s1, const std::string& s2, int opt); + int mystrlen(const char* word); + int leftcommonsubstring(const char* s1, const char* s2); + int commoncharacterpositions(const char* s1, const char* s2, int* is_swap); + void bubblesort(char** rwd, char** rwd2, int* rsc, int n); + void lcs(const char* s, const char* s2, int* l1, int* l2, char** result); + int lcslen(const char* s, const char* s2); + int lcslen(const std::string& s, const std::string& s2); + char* suggest_hentry_gen(hentry* rv, const char* pattern); +}; + +#endif diff --git a/extensions/spellcheck/hunspell/src/w_char.hxx b/extensions/spellcheck/hunspell/src/w_char.hxx new file mode 100644 index 000000000..336c454f7 --- /dev/null +++ b/extensions/spellcheck/hunspell/src/w_char.hxx @@ -0,0 +1,75 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno, + * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád, + * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter, + * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls, + * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __WCHARHXX__ +#define __WCHARHXX__ + +#ifndef GCC +struct w_char { +#else +struct __attribute__((packed)) w_char { +#endif + unsigned char l; + unsigned char h; + + friend bool operator<(const w_char a, const w_char b) { + unsigned short a_idx = (a.h << 8) + a.l; + unsigned short b_idx = (b.h << 8) + b.l; + return a_idx < b_idx; + } + + friend bool operator==(const w_char a, const w_char b) { + return (((a).l == (b).l) && ((a).h == (b).h)); + } + + friend bool operator!=(const w_char a, const w_char b) { + return !(a == b);; + } +}; + +// two character arrays +struct replentry { + char* pattern; + char* pattern2; + bool start; + bool end; +}; + +#endif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff new file mode 100644 index 000000000..0a11404fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.aff @@ -0,0 +1,4 @@ +# capitalized ngram suggestion test data (Unicode version) for +# Sf.net Bug ID 1463589, reported by Frederik Fouvry. +SET UTF-8 +MAXNGRAMSUGS 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic new file mode 100644 index 000000000..8cec60603 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.dic @@ -0,0 +1,2 @@ +1 +Kühlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug new file mode 100644 index 000000000..8a72f1e21 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.sug @@ -0,0 +1,5 @@ +Kühlschrank +Kühlschrank +Kühlschrank +Kühlschrank +Kühlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong new file mode 100644 index 000000000..9de6c63cd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589-utf.wrong @@ -0,0 +1,5 @@ +kuhlschrank +kuehlschrank +kühlschrank +Kuhlschrank +Kuehlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff b/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff new file mode 100644 index 000000000..8ecf4594e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.aff @@ -0,0 +1,3 @@ +# capitalized ngram suggestion test data for +# Sf.net Bug ID 1463589, reported by Frederik Fouvry. +MAXNGRAMSUGS 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic b/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic new file mode 100644 index 000000000..a3caab802 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.dic @@ -0,0 +1,2 @@ +1 +Khlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug b/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug new file mode 100644 index 000000000..2961eddd2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.sug @@ -0,0 +1,5 @@ +Khlschrank +Khlschrank +Khlschrank +Khlschrank +Khlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.test b/extensions/spellcheck/hunspell/tests/unit/data/1463589.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong new file mode 100644 index 000000000..0f3f48969 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1463589.wrong @@ -0,0 +1,5 @@ +kuhlschrank +kuehlschrank +khlschrank +Kuhlschrank +Kuehlschrank diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff b/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff new file mode 100644 index 000000000..0aa064e37 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.aff @@ -0,0 +1,20 @@ +# fix homonym handling for German dictionary project, +# reported by Björn Jacke (sf.net Bug ID 1592880). +SET ISO8859-1 + +SFX N Y 1 +SFX N 0 n . + +SFX S Y 1 +SFX S 0 s . + +SFX P Y 1 +SFX P 0 en . + +SFX Q Y 2 +SFX Q 0 e . +SFX Q 0 en . + +COMPOUNDEND z +COMPOUNDPERMITFLAG c +ONLYINCOMPOUND o diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic b/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic new file mode 100644 index 000000000..8b0fef814 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.dic @@ -0,0 +1,4 @@ +3 +weg/Qoz +weg/P +wege diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.good b/extensions/spellcheck/hunspell/tests/unit/data/1592880.good new file mode 100644 index 000000000..aa00a58b1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.good @@ -0,0 +1,3 @@ +weg +wege +wegen diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1592880.test b/extensions/spellcheck/hunspell/tests/unit/data/1592880.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1592880.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff b/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff new file mode 100644 index 000000000..359a25f3a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.aff @@ -0,0 +1,10 @@ +# fix NEEDAFFIX homonym suggestion. +# Sf.net Bug ID 1695964, reported by Björn Jacke. +TRY esianrtolcdugmphbyfvkwESIANRTOLCDUGMPHBYFVKW +MAXNGRAMSUGS 0 +NEEDAFFIX h +SFX S Y 1 +SFX S 0 s . + +SFX e Y 1 +SFX e 0 e . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic b/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic new file mode 100644 index 000000000..ff6d110cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.dic @@ -0,0 +1,3 @@ +2 +Mull/he +Mull/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug b/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug new file mode 100644 index 000000000..35aedff7c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.sug @@ -0,0 +1,3 @@ +Mull +Mulle +Mulls diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.test b/extensions/spellcheck/hunspell/tests/unit/data/1695964.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong new file mode 100644 index 000000000..fd13dc8ca --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1695964.wrong @@ -0,0 +1,3 @@ +Mall +Malle +Malls diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff b/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff new file mode 100644 index 000000000..66a676efa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.aff @@ -0,0 +1,13 @@ +# test COMPOUNDRULE bug reported by Björn Jacke +SET ISO8859-1 +TRY esijanrtolcdugmphbyfvkwqxz + +SFX A Y 5 +SFX A 0 e . +SFX A 0 er . +SFX A 0 en . +SFX A 0 em . +SFX A 0 es . + +COMPOUNDRULE 1 +COMPOUNDRULE vw diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic b/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic new file mode 100644 index 000000000..32d461f7a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.dic @@ -0,0 +1,4 @@ +3 +arbeits/v +scheu/Aw +farbig/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.test b/extensions/spellcheck/hunspell/tests/unit/data/1706659.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong new file mode 100644 index 000000000..799dd3111 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1706659.wrong @@ -0,0 +1,3 @@ +arbeitsfarbig +arbeitsfarbige +arbeitsfarbiger diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff b/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff new file mode 100644 index 000000000..0912050d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.aff @@ -0,0 +1,6 @@ +SET UTF-8 +IGNORE ٌٍَُِّْـ + +PFX x N 1 +PFX x أ ت أ[^ي] + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic b/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic new file mode 100644 index 000000000..b1b455df5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.dic @@ -0,0 +1,3 @@ +2 +أرى/x +أيار/x diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.good b/extensions/spellcheck/hunspell/tests/unit/data/1975530.good new file mode 100644 index 000000000..89212a57e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.good @@ -0,0 +1,3 @@ +أرى +أيار +ترى diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.test b/extensions/spellcheck/hunspell/tests/unit/data/1975530.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong b/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong new file mode 100644 index 000000000..24cb57627 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/1975530.wrong @@ -0,0 +1 @@ +تيار diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff b/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff new file mode 100644 index 000000000..6ef95161d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.aff @@ -0,0 +1,5 @@ +# test words with three parts +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN le fi +COMPOUNDFLAG c + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic b/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic new file mode 100644 index 000000000..f0b630569 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.dic @@ -0,0 +1,4 @@ +3 +first/c +middle/c +last/c diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.good b/extensions/spellcheck/hunspell/tests/unit/data/2970240.good new file mode 100644 index 000000000..a8d3a593b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.good @@ -0,0 +1 @@ +firstmiddlelast diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.test b/extensions/spellcheck/hunspell/tests/unit/data/2970240.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong b/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong new file mode 100644 index 000000000..32cead611 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970240.wrong @@ -0,0 +1 @@ +lastmiddlefirst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff b/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff new file mode 100644 index 000000000..909f0fbc3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.aff @@ -0,0 +1,4 @@ +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN /a /b +COMPOUNDFLAG c + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic b/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic new file mode 100644 index 000000000..da0d05f92 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.dic @@ -0,0 +1,4 @@ +3 +foo/ac +bar/c +baz/bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.good b/extensions/spellcheck/hunspell/tests/unit/data/2970242.good new file mode 100644 index 000000000..90ecb182f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.good @@ -0,0 +1,5 @@ +foobar +barfoo +bazfoo +barbaz +bazbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.test b/extensions/spellcheck/hunspell/tests/unit/data/2970242.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong b/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong new file mode 100644 index 000000000..9dabfec91 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2970242.wrong @@ -0,0 +1 @@ +foobaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff b/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff new file mode 100644 index 000000000..ea9d0b07b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.aff @@ -0,0 +1,6 @@ +COMPOUNDRULE 1 +COMPOUNDRULE ab + +COMPOUNDBEGIN A +COMPOUNDEND B + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic b/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic new file mode 100644 index 000000000..249860362 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.dic @@ -0,0 +1,4 @@ +3 +foo/aA +bar/b +baz/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.good b/extensions/spellcheck/hunspell/tests/unit/data/2999225.good new file mode 100644 index 000000000..865e15452 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.good @@ -0,0 +1,2 @@ +foobar +foobaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/2999225.test b/extensions/spellcheck/hunspell/tests/unit/data/2999225.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/2999225.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff b/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff new file mode 100644 index 000000000..c817c2e91 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.aff @@ -0,0 +1,8 @@ +# check bad capitalisation of Dutch letter IJ. +TRY i +FORBIDDENWORD * +PFX i N 1 +PFX i ij IJ ij + +REP 1 +REP ij IJ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic b/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic new file mode 100644 index 000000000..ecaf91d21 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.dic @@ -0,0 +1,3 @@ +1 +ijs/i +Ijs/* diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.good b/extensions/spellcheck/hunspell/tests/unit/data/IJ.good new file mode 100644 index 000000000..5f888f057 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.good @@ -0,0 +1,2 @@ +ijs +IJs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug b/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug new file mode 100644 index 000000000..582b7956b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.sug @@ -0,0 +1 @@ +IJs, ijs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.test b/extensions/spellcheck/hunspell/tests/unit/data/IJ.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong b/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong new file mode 100644 index 000000000..54bbb475a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/IJ.wrong @@ -0,0 +1 @@ +Ijs diff --git a/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am new file mode 100644 index 000000000..8018ccf7b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.am @@ -0,0 +1,693 @@ +## Process this file with automake to create Makefile.in + +SUBDIRS = suggestiontest + +XFAIL_TESTS = @XFAILED@ + +TESTS = \ +affixes.test \ +condition.test \ +condition_utf.test \ +base.test \ +base_utf.test \ +allcaps.test \ +allcaps_utf.test \ +allcaps2.test \ +allcaps3.test \ +keepcase.test \ +i58202.test \ +map.test \ +rep.test \ +sug.test \ +sugutf.test \ +phone.test \ +flag.test \ +flaglong.test \ +flagnum.test \ +flagutf8.test \ +slash.test \ +forbiddenword.test \ +nosuggest.test \ +alias.test \ +alias2.test \ +alias3.test \ +breakdefault.test \ +break.test \ +needaffix.test \ +needaffix2.test \ +needaffix3.test \ +needaffix4.test \ +needaffix5.test \ +circumfix.test \ +fogemorpheme.test \ +onlyincompound.test \ +complexprefixes.test \ +complexprefixes2.test \ +complexprefixesutf.test \ +conditionalprefix.test \ +zeroaffix.test \ +utf8.test \ +utf8_bom.test \ +utf8_bom2.test \ +utf8_nonbmp.test \ +compoundflag.test \ +compoundrule.test \ +compoundrule2.test \ +compoundrule3.test \ +compoundrule4.test \ +compoundrule5.test \ +compoundrule6.test \ +compoundrule7.test \ +compoundrule8.test \ +compoundaffix.test \ +compoundaffix2.test \ +compoundaffix3.test \ +checkcompounddup.test \ +checkcompoundtriple.test \ +simplifiedtriple.test \ +checkcompoundrep.test \ +checkcompoundcase2.test \ +checkcompoundcaseutf.test \ +checkcompoundpattern.test \ +checkcompoundpattern2.test \ +checkcompoundpattern3.test \ +checkcompoundpattern4.test \ +utfcompound.test \ +checksharps.test \ +checksharpsutf.test \ +germancompounding.test \ +germancompoundingold.test \ +i35725.test \ +i53643.test \ +i54633.test \ +i54980.test \ +maputf.test \ +reputf.test \ +ignore.test \ +ignoreutf.test \ +1592880.test \ +1695964.test \ +1463589.test \ +1463589_utf.test \ +IJ.test \ +i68568.test \ +i68568utf.test \ +1706659.test \ +digits_in_words.test \ +colons_in_words.test \ +ngram_utf_fix.test \ +morph.test \ +1975530.test \ +fullstrip.test \ +iconv.test \ +oconv.test \ +encoding.test \ +korean.test \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword2.test \ +opentaal_keepcase.test \ +arabic.test \ +2970240.test \ +2970242.test \ +breakoff.test \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.test \ +2999225.test \ +onlyincompound2.test \ +forceucase.test \ +warn.test + +# infixes.test + +distclean-local: + -rm -rf testSubDir + +EXTRA_DIST = \ +test.sh \ +affixes.aff \ +affixes.dic \ +affixes.good \ +affixes.test \ +condition.aff \ +condition.dic \ +condition.good \ +condition.test \ +condition.wrong \ +condition_utf.aff \ +condition_utf.dic \ +condition_utf.good \ +condition_utf.test \ +condition_utf.wrong \ +base.aff \ +base.dic \ +base.good \ +base.sug \ +base.test \ +base.wrong \ +base_utf.aff \ +base_utf.dic \ +base_utf.good \ +base_utf.sug \ +base_utf.test \ +base_utf.wrong \ +allcaps.aff \ +allcaps.dic \ +allcaps.good \ +allcaps.sug \ +allcaps.test \ +allcaps.wrong \ +allcaps2.aff \ +allcaps2.dic \ +allcaps2.good \ +allcaps2.sug \ +allcaps2.test \ +allcaps2.wrong \ +allcaps3.aff \ +allcaps3.dic \ +allcaps3.good \ +allcaps3.test \ +allcaps3.wrong \ +allcaps_utf.aff \ +allcaps_utf.dic \ +allcaps_utf.good \ +allcaps_utf.sug \ +allcaps_utf.test \ +allcaps_utf.wrong \ +keepcase.aff \ +keepcase.dic \ +keepcase.good \ +keepcase.sug \ +keepcase.test \ +keepcase.wrong \ +map.aff \ +map.dic \ +map.sug \ +map.test \ +map.wrong \ +rep.aff \ +rep.dic \ +rep.sug \ +rep.test \ +rep.wrong \ +sug.aff \ +sug.dic \ +sug.sug \ +sug.test \ +sug.wrong \ +sugutf.aff \ +sugutf.dic \ +sugutf.sug \ +sugutf.test \ +sugutf.wrong \ +phone.aff \ +phone.dic \ +phone.sug \ +phone.test \ +phone.wrong \ +alias.aff \ +alias.dic \ +alias.good \ +alias.test \ +alias2.aff \ +alias2.dic \ +alias2.good \ +alias2.morph \ +alias2.test \ +alias3.aff \ +alias3.dic \ +alias3.good \ +alias3.morph \ +alias3.test \ +break.aff \ +break.dic \ +break.good \ +break.test \ +break.wrong \ +breakdefault.aff \ +breakdefault.dic \ +breakdefault.good \ +breakdefault.sug \ +breakdefault.test \ +breakdefault.wrong \ +circumfix.aff \ +circumfix.dic \ +circumfix.good \ +circumfix.morph \ +circumfix.test \ +circumfix.wrong \ +fogemorpheme.aff \ +fogemorpheme.dic \ +fogemorpheme.good \ +fogemorpheme.test \ +fogemorpheme.wrong \ +onlyincompound.aff \ +onlyincompound.dic \ +onlyincompound.good \ +onlyincompound.sug \ +onlyincompound.test \ +onlyincompound.wrong \ +forbiddenword.aff \ +forbiddenword.dic \ +forbiddenword.good \ +forbiddenword.test \ +forbiddenword.wrong \ +nosuggest.aff \ +nosuggest.dic \ +nosuggest.good \ +nosuggest.sug \ +nosuggest.test \ +nosuggest.wrong \ +germancompounding.aff \ +germancompounding.dic \ +germancompounding.good \ +germancompounding.test \ +germancompounding.wrong \ +germancompoundingold.aff \ +germancompoundingold.dic \ +germancompoundingold.good \ +germancompoundingold.test \ +germancompoundingold.wrong \ +needaffix2.aff \ +needaffix2.dic \ +needaffix2.good \ +needaffix2.morph \ +needaffix2.test \ +needaffix3.aff \ +needaffix3.dic \ +needaffix3.good \ +needaffix3.test \ +needaffix3.wrong \ +needaffix4.aff \ +needaffix4.dic \ +needaffix4.good \ +needaffix4.test \ +needaffix5.aff \ +needaffix5.dic \ +needaffix5.good \ +needaffix5.test \ +needaffix5.wrong \ +needaffix.aff \ +needaffix.dic \ +needaffix.good \ +needaffix.test \ +needaffix.wrong \ +zeroaffix.aff \ +zeroaffix.dic \ +zeroaffix.good \ +zeroaffix.morph \ +zeroaffix.test \ +utf8.aff \ +utf8.dic \ +utf8.good \ +utf8.test \ +utf8_bom.aff \ +utf8_bom.dic \ +utf8_bom.good \ +utf8_bom.test \ +utf8_bom2.aff \ +utf8_bom2.dic \ +utf8_bom2.good \ +utf8_bom2.test \ +utf8_nonbmp.aff \ +utf8_nonbmp.dic \ +utf8_nonbmp.good \ +utf8_nonbmp.sug \ +utf8_nonbmp.test \ +utf8_nonbmp.wrong \ +utfcompound.aff \ +utfcompound.dic \ +utfcompound.good \ +utfcompound.test \ +utfcompound.wrong \ +compoundflag.aff \ +compoundflag.dic \ +compoundflag.good \ +compoundflag.test \ +compoundflag.wrong \ +compoundrule.aff \ +compoundrule.dic \ +compoundrule.good \ +compoundrule.test \ +compoundrule.wrong \ +compoundrule2.aff \ +compoundrule2.dic \ +compoundrule2.good \ +compoundrule2.test \ +compoundrule2.wrong \ +compoundrule3.aff \ +compoundrule3.dic \ +compoundrule3.good \ +compoundrule3.test \ +compoundrule3.wrong \ +compoundrule4.aff \ +compoundrule4.dic \ +compoundrule4.good \ +compoundrule4.test \ +compoundrule4.wrong \ +compoundrule5.aff \ +compoundrule5.dic \ +compoundrule5.good \ +compoundrule5.morph \ +compoundrule5.test \ +compoundrule5.wrong \ +compoundrule6.aff \ +compoundrule6.dic \ +compoundrule6.good \ +compoundrule6.test \ +compoundrule6.wrong \ +compoundrule7.aff \ +compoundrule7.dic \ +compoundrule7.good \ +compoundrule7.test \ +compoundrule7.wrong \ +compoundrule8.aff \ +compoundrule8.dic \ +compoundrule8.good \ +compoundrule8.test \ +compoundrule8.wrong \ +compoundaffix.aff \ +compoundaffix.dic \ +compoundaffix.good \ +compoundaffix.test \ +compoundaffix.wrong \ +compoundaffix2.aff \ +compoundaffix2.dic \ +compoundaffix2.good \ +compoundaffix2.test \ +compoundaffix3.aff \ +compoundaffix3.dic \ +compoundaffix3.good \ +compoundaffix3.test \ +compoundaffix3.wrong \ +checkcompounddup.aff \ +checkcompounddup.dic \ +checkcompounddup.good \ +checkcompounddup.test \ +checkcompounddup.wrong \ +checkcompoundcase.aff \ +checkcompoundcase.dic \ +checkcompoundcase.good \ +checkcompoundcase.test \ +checkcompoundcase.wrong \ +checkcompoundcase2.aff \ +checkcompoundcase2.dic \ +checkcompoundcase2.good \ +checkcompoundcase2.test \ +checkcompoundcase2.wrong \ +checkcompoundcaseutf.aff \ +checkcompoundcaseutf.dic \ +checkcompoundcaseutf.good \ +checkcompoundcaseutf.test \ +checkcompoundcaseutf.wrong \ +checkcompoundrep.aff \ +checkcompoundrep.dic \ +checkcompoundrep.good \ +checkcompoundrep.test \ +checkcompoundrep.wrong \ +checkcompoundtriple.aff \ +checkcompoundtriple.dic \ +checkcompoundtriple.good \ +checkcompoundtriple.test \ +checkcompoundtriple.wrong \ +simplifiedtriple.aff \ +simplifiedtriple.dic \ +simplifiedtriple.good \ +simplifiedtriple.test \ +simplifiedtriple.wrong \ +checkcompoundpattern.aff \ +checkcompoundpattern.dic \ +checkcompoundpattern.good \ +checkcompoundpattern.test \ +checkcompoundpattern.wrong \ +checkcompoundpattern2.aff \ +checkcompoundpattern2.dic \ +checkcompoundpattern2.good \ +checkcompoundpattern2.test \ +checkcompoundpattern2.wrong \ +checkcompoundpattern3.aff \ +checkcompoundpattern3.dic \ +checkcompoundpattern3.good \ +checkcompoundpattern3.test \ +checkcompoundpattern3.wrong \ +checkcompoundpattern4.aff \ +checkcompoundpattern4.dic \ +checkcompoundpattern4.good \ +checkcompoundpattern4.test \ +checkcompoundpattern4.wrong \ +checksharps.aff \ +checksharps.dic \ +checksharps.good \ +checksharps.sug \ +checksharps.test \ +checksharps.wrong \ +checksharpsutf.aff \ +checksharpsutf.dic \ +checksharpsutf.good \ +checksharpsutf.sug \ +checksharpsutf.test \ +checksharpsutf.wrong \ +conditionalprefix.aff \ +conditionalprefix.dic \ +conditionalprefix.good \ +conditionalprefix.morph \ +conditionalprefix.test \ +conditionalprefix.wrong \ +flaglong.aff \ +flaglong.dic \ +flaglong.good \ +flaglong.test \ +flagnum.aff \ +flagnum.dic \ +flagnum.good \ +flagnum.test \ +flag.aff \ +flag.dic \ +flag.good \ +flag.test \ +flagutf8.aff \ +flagutf8.dic \ +flagutf8.good \ +flagutf8.test \ +complexprefixes.aff \ +complexprefixes.dic \ +complexprefixes.good \ +complexprefixes.wrong \ +complexprefixes.test \ +complexprefixes2.aff \ +complexprefixes2.dic \ +complexprefixes2.good \ +complexprefixes2.test \ +complexprefixesutf.aff \ +complexprefixesutf.dic \ +complexprefixesutf.good \ +complexprefixesutf.wrong \ +complexprefixesutf.test \ +i35725.aff \ +i35725.dic \ +i35725.good \ +i35725.sug \ +i35725.test \ +i35725.wrong \ +i53643.aff \ +i53643.dic \ +i53643.good \ +i53643.test \ +i53643.wrong \ +i54633.aff \ +i54633.dic \ +i54633.good \ +i54633.sug \ +i54633.test \ +i54633.wrong \ +i54980.aff \ +i54980.dic \ +i54980.good \ +i54980.test \ +i58202.aff \ +i58202.dic \ +i58202.good \ +i58202.sug \ +i58202.test \ +i58202.wrong \ +maputf.aff \ +maputf.dic \ +maputf.sug \ +maputf.wrong \ +maputf.test \ +reputf.aff \ +reputf.dic \ +reputf.sug \ +reputf.wrong \ +reputf.test \ +slash.aff \ +slash.dic \ +slash.good \ +slash.test \ +ignore.aff \ +ignore.dic \ +ignore.good \ +ignore.test \ +ignoreutf.aff \ +ignoreutf.dic \ +ignoreutf.good \ +ignoreutf.test \ +1592880.aff \ +1592880.dic \ +1592880.good \ +1592880.test \ +1695964.aff \ +1695964.dic \ +1695964.sug \ +1695964.test \ +1695964.wrong \ +1463589.aff \ +1463589.dic \ +1463589.sug \ +1463589.test \ +1463589.wrong \ +1463589_utf.aff \ +1463589_utf.dic \ +1463589_utf.sug \ +1463589_utf.test \ +1463589_utf.wrong \ +IJ.aff \ +IJ.dic \ +IJ.good \ +IJ.sug \ +IJ.test \ +IJ.wrong \ +i68568.aff \ +i68568.dic \ +i68568.test \ +i68568.wrong \ +i68568utf.aff \ +i68568utf.dic \ +i68568utf.test \ +i68568utf.wrong \ +1706659.aff \ +1706659.dic \ +1706659.test \ +1706659.wrong \ +digits_in_words.aff \ +digits_in_words.dic \ +digits_in_words.test \ +digits_in_words.wrong \ +colons_in_words.aff \ +colons_in_words.dic \ +colons_in_words.test \ +ngram_utf_fix.aff \ +ngram_utf_fix.dic \ +ngram_utf_fix.good \ +ngram_utf_fix.sug \ +ngram_utf_fix.test \ +ngram_utf_fix.wrong \ +morph.aff \ +morph.dic \ +morph.good \ +morph.morph \ +morph.test \ +1975530.aff \ +1975530.dic \ +1975530.good \ +1975530.test \ +1975530.wrong \ +fullstrip.aff \ +fullstrip.dic \ +fullstrip.good \ +fullstrip.test \ +iconv.aff \ +iconv.dic \ +iconv.good \ +iconv.test \ +oconv.aff \ +oconv.dic \ +oconv.good \ +oconv.sug \ +oconv.test \ +oconv.wrong \ +encoding.aff \ +encoding.dic \ +encoding.good \ +encoding.test \ +opentaal_forbiddenword1.aff \ +opentaal_forbiddenword1.dic \ +opentaal_forbiddenword1.good \ +opentaal_forbiddenword1.sug \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword1.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_keepcase.aff \ +opentaal_keepcase.dic \ +opentaal_keepcase.good \ +opentaal_keepcase.sug \ +opentaal_keepcase.test \ +opentaal_keepcase.wrong \ +arabic.aff \ +arabic.dic \ +arabic.wrong \ +arabic.test \ +2970240.aff \ +2970240.dic \ +2970240.good \ +2970240.wrong \ +2970240.test \ +2970242.aff \ +2970242.dic \ +2970242.good \ +2970242.wrong \ +2970242.test \ +breakoff.aff \ +breakoff.dic \ +breakoff.good \ +breakoff.wrong \ +breakoff.test \ +opentaal_cpdpat.aff \ +opentaal_cpdpat.dic \ +opentaal_cpdpat.good \ +opentaal_cpdpat.wrong \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.aff \ +opentaal_cpdpat2.dic \ +opentaal_cpdpat2.good \ +opentaal_cpdpat2.wrong \ +opentaal_cpdpat2.test \ +2999225.aff \ +2999225.dic \ +2999225.good \ +2999225.test \ +korean.aff \ +korean.dic \ +korean.good \ +korean.wrong \ +korean.test \ +onlyincompound2.aff \ +onlyincompound2.dic \ +onlyincompound2.good \ +onlyincompound2.test \ +onlyincompound2.wrong \ +forceucase.aff \ +forceucase.dic \ +forceucase.good \ +forceucase.sug \ +forceucase.wrong \ +forceucase.test \ +warn.aff \ +warn.dic \ +warn.good \ +warn.test + +# infixes.aff +# infixes.dic +# infixes.good +# infixes.test diff --git a/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in new file mode 100644 index 000000000..a27e04875 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/Makefile.in @@ -0,0 +1,1416 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \ + $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSESLIB = @CURSESLIB@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENCAT = @GENCAT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC2 = @GLIBC2@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_VISIBILITY = @HAVE_VISIBILITY@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HUNSPELL_VERSION_MAJOR = @HUNSPELL_VERSION_MAJOR@ +HUNSPELL_VERSION_MINOR = @HUNSPELL_VERSION_MINOR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBC = @LTLIBC@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +WOE32 = @WOE32@ +WOE32DLL = @WOE32DLL@ +XFAILED = @XFAILED@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = suggestiontest +XFAIL_TESTS = @XFAILED@ +TESTS = \ +affixes.test \ +condition.test \ +condition_utf.test \ +base.test \ +base_utf.test \ +allcaps.test \ +allcaps_utf.test \ +allcaps2.test \ +allcaps3.test \ +keepcase.test \ +i58202.test \ +map.test \ +rep.test \ +sug.test \ +sugutf.test \ +phone.test \ +flag.test \ +flaglong.test \ +flagnum.test \ +flagutf8.test \ +slash.test \ +forbiddenword.test \ +nosuggest.test \ +alias.test \ +alias2.test \ +alias3.test \ +breakdefault.test \ +break.test \ +needaffix.test \ +needaffix2.test \ +needaffix3.test \ +needaffix4.test \ +needaffix5.test \ +circumfix.test \ +fogemorpheme.test \ +onlyincompound.test \ +complexprefixes.test \ +complexprefixes2.test \ +complexprefixesutf.test \ +conditionalprefix.test \ +zeroaffix.test \ +utf8.test \ +utf8_bom.test \ +utf8_bom2.test \ +utf8_nonbmp.test \ +compoundflag.test \ +compoundrule.test \ +compoundrule2.test \ +compoundrule3.test \ +compoundrule4.test \ +compoundrule5.test \ +compoundrule6.test \ +compoundrule7.test \ +compoundrule8.test \ +compoundaffix.test \ +compoundaffix2.test \ +compoundaffix3.test \ +checkcompounddup.test \ +checkcompoundtriple.test \ +simplifiedtriple.test \ +checkcompoundrep.test \ +checkcompoundcase2.test \ +checkcompoundcaseutf.test \ +checkcompoundpattern.test \ +checkcompoundpattern2.test \ +checkcompoundpattern3.test \ +checkcompoundpattern4.test \ +utfcompound.test \ +checksharps.test \ +checksharpsutf.test \ +germancompounding.test \ +germancompoundingold.test \ +i35725.test \ +i53643.test \ +i54633.test \ +i54980.test \ +maputf.test \ +reputf.test \ +ignore.test \ +ignoreutf.test \ +1592880.test \ +1695964.test \ +1463589.test \ +1463589_utf.test \ +IJ.test \ +i68568.test \ +i68568utf.test \ +1706659.test \ +digits_in_words.test \ +colons_in_words.test \ +ngram_utf_fix.test \ +morph.test \ +1975530.test \ +fullstrip.test \ +iconv.test \ +oconv.test \ +encoding.test \ +korean.test \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword2.test \ +opentaal_keepcase.test \ +arabic.test \ +2970240.test \ +2970242.test \ +breakoff.test \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.test \ +2999225.test \ +onlyincompound2.test \ +forceucase.test \ +warn.test + +EXTRA_DIST = \ +test.sh \ +affixes.aff \ +affixes.dic \ +affixes.good \ +affixes.test \ +condition.aff \ +condition.dic \ +condition.good \ +condition.test \ +condition.wrong \ +condition_utf.aff \ +condition_utf.dic \ +condition_utf.good \ +condition_utf.test \ +condition_utf.wrong \ +base.aff \ +base.dic \ +base.good \ +base.sug \ +base.test \ +base.wrong \ +base_utf.aff \ +base_utf.dic \ +base_utf.good \ +base_utf.sug \ +base_utf.test \ +base_utf.wrong \ +allcaps.aff \ +allcaps.dic \ +allcaps.good \ +allcaps.sug \ +allcaps.test \ +allcaps.wrong \ +allcaps2.aff \ +allcaps2.dic \ +allcaps2.good \ +allcaps2.sug \ +allcaps2.test \ +allcaps2.wrong \ +allcaps3.aff \ +allcaps3.dic \ +allcaps3.good \ +allcaps3.test \ +allcaps3.wrong \ +allcaps_utf.aff \ +allcaps_utf.dic \ +allcaps_utf.good \ +allcaps_utf.sug \ +allcaps_utf.test \ +allcaps_utf.wrong \ +keepcase.aff \ +keepcase.dic \ +keepcase.good \ +keepcase.sug \ +keepcase.test \ +keepcase.wrong \ +map.aff \ +map.dic \ +map.sug \ +map.test \ +map.wrong \ +rep.aff \ +rep.dic \ +rep.sug \ +rep.test \ +rep.wrong \ +sug.aff \ +sug.dic \ +sug.sug \ +sug.test \ +sug.wrong \ +sugutf.aff \ +sugutf.dic \ +sugutf.sug \ +sugutf.test \ +sugutf.wrong \ +phone.aff \ +phone.dic \ +phone.sug \ +phone.test \ +phone.wrong \ +alias.aff \ +alias.dic \ +alias.good \ +alias.test \ +alias2.aff \ +alias2.dic \ +alias2.good \ +alias2.morph \ +alias2.test \ +alias3.aff \ +alias3.dic \ +alias3.good \ +alias3.morph \ +alias3.test \ +break.aff \ +break.dic \ +break.good \ +break.test \ +break.wrong \ +breakdefault.aff \ +breakdefault.dic \ +breakdefault.good \ +breakdefault.sug \ +breakdefault.test \ +breakdefault.wrong \ +circumfix.aff \ +circumfix.dic \ +circumfix.good \ +circumfix.morph \ +circumfix.test \ +circumfix.wrong \ +fogemorpheme.aff \ +fogemorpheme.dic \ +fogemorpheme.good \ +fogemorpheme.test \ +fogemorpheme.wrong \ +onlyincompound.aff \ +onlyincompound.dic \ +onlyincompound.good \ +onlyincompound.sug \ +onlyincompound.test \ +onlyincompound.wrong \ +forbiddenword.aff \ +forbiddenword.dic \ +forbiddenword.good \ +forbiddenword.test \ +forbiddenword.wrong \ +nosuggest.aff \ +nosuggest.dic \ +nosuggest.good \ +nosuggest.sug \ +nosuggest.test \ +nosuggest.wrong \ +germancompounding.aff \ +germancompounding.dic \ +germancompounding.good \ +germancompounding.test \ +germancompounding.wrong \ +germancompoundingold.aff \ +germancompoundingold.dic \ +germancompoundingold.good \ +germancompoundingold.test \ +germancompoundingold.wrong \ +needaffix2.aff \ +needaffix2.dic \ +needaffix2.good \ +needaffix2.morph \ +needaffix2.test \ +needaffix3.aff \ +needaffix3.dic \ +needaffix3.good \ +needaffix3.test \ +needaffix3.wrong \ +needaffix4.aff \ +needaffix4.dic \ +needaffix4.good \ +needaffix4.test \ +needaffix5.aff \ +needaffix5.dic \ +needaffix5.good \ +needaffix5.test \ +needaffix5.wrong \ +needaffix.aff \ +needaffix.dic \ +needaffix.good \ +needaffix.test \ +needaffix.wrong \ +zeroaffix.aff \ +zeroaffix.dic \ +zeroaffix.good \ +zeroaffix.morph \ +zeroaffix.test \ +utf8.aff \ +utf8.dic \ +utf8.good \ +utf8.test \ +utf8_bom.aff \ +utf8_bom.dic \ +utf8_bom.good \ +utf8_bom.test \ +utf8_bom2.aff \ +utf8_bom2.dic \ +utf8_bom2.good \ +utf8_bom2.test \ +utf8_nonbmp.aff \ +utf8_nonbmp.dic \ +utf8_nonbmp.good \ +utf8_nonbmp.sug \ +utf8_nonbmp.test \ +utf8_nonbmp.wrong \ +utfcompound.aff \ +utfcompound.dic \ +utfcompound.good \ +utfcompound.test \ +utfcompound.wrong \ +compoundflag.aff \ +compoundflag.dic \ +compoundflag.good \ +compoundflag.test \ +compoundflag.wrong \ +compoundrule.aff \ +compoundrule.dic \ +compoundrule.good \ +compoundrule.test \ +compoundrule.wrong \ +compoundrule2.aff \ +compoundrule2.dic \ +compoundrule2.good \ +compoundrule2.test \ +compoundrule2.wrong \ +compoundrule3.aff \ +compoundrule3.dic \ +compoundrule3.good \ +compoundrule3.test \ +compoundrule3.wrong \ +compoundrule4.aff \ +compoundrule4.dic \ +compoundrule4.good \ +compoundrule4.test \ +compoundrule4.wrong \ +compoundrule5.aff \ +compoundrule5.dic \ +compoundrule5.good \ +compoundrule5.morph \ +compoundrule5.test \ +compoundrule5.wrong \ +compoundrule6.aff \ +compoundrule6.dic \ +compoundrule6.good \ +compoundrule6.test \ +compoundrule6.wrong \ +compoundrule7.aff \ +compoundrule7.dic \ +compoundrule7.good \ +compoundrule7.test \ +compoundrule7.wrong \ +compoundrule8.aff \ +compoundrule8.dic \ +compoundrule8.good \ +compoundrule8.test \ +compoundrule8.wrong \ +compoundaffix.aff \ +compoundaffix.dic \ +compoundaffix.good \ +compoundaffix.test \ +compoundaffix.wrong \ +compoundaffix2.aff \ +compoundaffix2.dic \ +compoundaffix2.good \ +compoundaffix2.test \ +compoundaffix3.aff \ +compoundaffix3.dic \ +compoundaffix3.good \ +compoundaffix3.test \ +compoundaffix3.wrong \ +checkcompounddup.aff \ +checkcompounddup.dic \ +checkcompounddup.good \ +checkcompounddup.test \ +checkcompounddup.wrong \ +checkcompoundcase.aff \ +checkcompoundcase.dic \ +checkcompoundcase.good \ +checkcompoundcase.test \ +checkcompoundcase.wrong \ +checkcompoundcase2.aff \ +checkcompoundcase2.dic \ +checkcompoundcase2.good \ +checkcompoundcase2.test \ +checkcompoundcase2.wrong \ +checkcompoundcaseutf.aff \ +checkcompoundcaseutf.dic \ +checkcompoundcaseutf.good \ +checkcompoundcaseutf.test \ +checkcompoundcaseutf.wrong \ +checkcompoundrep.aff \ +checkcompoundrep.dic \ +checkcompoundrep.good \ +checkcompoundrep.test \ +checkcompoundrep.wrong \ +checkcompoundtriple.aff \ +checkcompoundtriple.dic \ +checkcompoundtriple.good \ +checkcompoundtriple.test \ +checkcompoundtriple.wrong \ +simplifiedtriple.aff \ +simplifiedtriple.dic \ +simplifiedtriple.good \ +simplifiedtriple.test \ +simplifiedtriple.wrong \ +checkcompoundpattern.aff \ +checkcompoundpattern.dic \ +checkcompoundpattern.good \ +checkcompoundpattern.test \ +checkcompoundpattern.wrong \ +checkcompoundpattern2.aff \ +checkcompoundpattern2.dic \ +checkcompoundpattern2.good \ +checkcompoundpattern2.test \ +checkcompoundpattern2.wrong \ +checkcompoundpattern3.aff \ +checkcompoundpattern3.dic \ +checkcompoundpattern3.good \ +checkcompoundpattern3.test \ +checkcompoundpattern3.wrong \ +checkcompoundpattern4.aff \ +checkcompoundpattern4.dic \ +checkcompoundpattern4.good \ +checkcompoundpattern4.test \ +checkcompoundpattern4.wrong \ +checksharps.aff \ +checksharps.dic \ +checksharps.good \ +checksharps.sug \ +checksharps.test \ +checksharps.wrong \ +checksharpsutf.aff \ +checksharpsutf.dic \ +checksharpsutf.good \ +checksharpsutf.sug \ +checksharpsutf.test \ +checksharpsutf.wrong \ +conditionalprefix.aff \ +conditionalprefix.dic \ +conditionalprefix.good \ +conditionalprefix.morph \ +conditionalprefix.test \ +conditionalprefix.wrong \ +flaglong.aff \ +flaglong.dic \ +flaglong.good \ +flaglong.test \ +flagnum.aff \ +flagnum.dic \ +flagnum.good \ +flagnum.test \ +flag.aff \ +flag.dic \ +flag.good \ +flag.test \ +flagutf8.aff \ +flagutf8.dic \ +flagutf8.good \ +flagutf8.test \ +complexprefixes.aff \ +complexprefixes.dic \ +complexprefixes.good \ +complexprefixes.wrong \ +complexprefixes.test \ +complexprefixes2.aff \ +complexprefixes2.dic \ +complexprefixes2.good \ +complexprefixes2.test \ +complexprefixesutf.aff \ +complexprefixesutf.dic \ +complexprefixesutf.good \ +complexprefixesutf.wrong \ +complexprefixesutf.test \ +i35725.aff \ +i35725.dic \ +i35725.good \ +i35725.sug \ +i35725.test \ +i35725.wrong \ +i53643.aff \ +i53643.dic \ +i53643.good \ +i53643.test \ +i53643.wrong \ +i54633.aff \ +i54633.dic \ +i54633.good \ +i54633.sug \ +i54633.test \ +i54633.wrong \ +i54980.aff \ +i54980.dic \ +i54980.good \ +i54980.test \ +i58202.aff \ +i58202.dic \ +i58202.good \ +i58202.sug \ +i58202.test \ +i58202.wrong \ +maputf.aff \ +maputf.dic \ +maputf.sug \ +maputf.wrong \ +maputf.test \ +reputf.aff \ +reputf.dic \ +reputf.sug \ +reputf.wrong \ +reputf.test \ +slash.aff \ +slash.dic \ +slash.good \ +slash.test \ +ignore.aff \ +ignore.dic \ +ignore.good \ +ignore.test \ +ignoreutf.aff \ +ignoreutf.dic \ +ignoreutf.good \ +ignoreutf.test \ +1592880.aff \ +1592880.dic \ +1592880.good \ +1592880.test \ +1695964.aff \ +1695964.dic \ +1695964.sug \ +1695964.test \ +1695964.wrong \ +1463589.aff \ +1463589.dic \ +1463589.sug \ +1463589.test \ +1463589.wrong \ +1463589_utf.aff \ +1463589_utf.dic \ +1463589_utf.sug \ +1463589_utf.test \ +1463589_utf.wrong \ +IJ.aff \ +IJ.dic \ +IJ.good \ +IJ.sug \ +IJ.test \ +IJ.wrong \ +i68568.aff \ +i68568.dic \ +i68568.test \ +i68568.wrong \ +i68568utf.aff \ +i68568utf.dic \ +i68568utf.test \ +i68568utf.wrong \ +1706659.aff \ +1706659.dic \ +1706659.test \ +1706659.wrong \ +digits_in_words.aff \ +digits_in_words.dic \ +digits_in_words.test \ +digits_in_words.wrong \ +colons_in_words.aff \ +colons_in_words.dic \ +colons_in_words.test \ +ngram_utf_fix.aff \ +ngram_utf_fix.dic \ +ngram_utf_fix.good \ +ngram_utf_fix.sug \ +ngram_utf_fix.test \ +ngram_utf_fix.wrong \ +morph.aff \ +morph.dic \ +morph.good \ +morph.morph \ +morph.test \ +1975530.aff \ +1975530.dic \ +1975530.good \ +1975530.test \ +1975530.wrong \ +fullstrip.aff \ +fullstrip.dic \ +fullstrip.good \ +fullstrip.test \ +iconv.aff \ +iconv.dic \ +iconv.good \ +iconv.test \ +oconv.aff \ +oconv.dic \ +oconv.good \ +oconv.sug \ +oconv.test \ +oconv.wrong \ +encoding.aff \ +encoding.dic \ +encoding.good \ +encoding.test \ +opentaal_forbiddenword1.aff \ +opentaal_forbiddenword1.dic \ +opentaal_forbiddenword1.good \ +opentaal_forbiddenword1.sug \ +opentaal_forbiddenword1.test \ +opentaal_forbiddenword1.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_forbiddenword2.aff \ +opentaal_forbiddenword2.dic \ +opentaal_forbiddenword2.good \ +opentaal_forbiddenword2.sug \ +opentaal_forbiddenword2.test \ +opentaal_forbiddenword2.wrong \ +opentaal_keepcase.aff \ +opentaal_keepcase.dic \ +opentaal_keepcase.good \ +opentaal_keepcase.sug \ +opentaal_keepcase.test \ +opentaal_keepcase.wrong \ +arabic.aff \ +arabic.dic \ +arabic.wrong \ +arabic.test \ +2970240.aff \ +2970240.dic \ +2970240.good \ +2970240.wrong \ +2970240.test \ +2970242.aff \ +2970242.dic \ +2970242.good \ +2970242.wrong \ +2970242.test \ +breakoff.aff \ +breakoff.dic \ +breakoff.good \ +breakoff.wrong \ +breakoff.test \ +opentaal_cpdpat.aff \ +opentaal_cpdpat.dic \ +opentaal_cpdpat.good \ +opentaal_cpdpat.wrong \ +opentaal_cpdpat.test \ +opentaal_cpdpat2.aff \ +opentaal_cpdpat2.dic \ +opentaal_cpdpat2.good \ +opentaal_cpdpat2.wrong \ +opentaal_cpdpat2.test \ +2999225.aff \ +2999225.dic \ +2999225.good \ +2999225.test \ +korean.aff \ +korean.dic \ +korean.good \ +korean.wrong \ +korean.test \ +onlyincompound2.aff \ +onlyincompound2.dic \ +onlyincompound2.good \ +onlyincompound2.test \ +onlyincompound2.wrong \ +forceucase.aff \ +forceucase.dic \ +forceucase.good \ +forceucase.sug \ +forceucase.wrong \ +forceucase.test \ +warn.aff \ +warn.dic \ +warn.good \ +warn.test + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-local \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean clean-generic \ + clean-libtool ctags ctags-recursive distclean \ + distclean-generic distclean-libtool distclean-local \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +# infixes.test + +distclean-local: + -rm -rf testSubDir + +# infixes.aff +# infixes.dic +# infixes.good +# infixes.test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff b/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff new file mode 100644 index 000000000..cf3c50021 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.aff @@ -0,0 +1,7 @@ +# simple example for affix compression (see Hunspell(4)) +PFX A Y 1 +PFX A 0 re . + +SFX B Y 2 +SFX B 0 ed [^y] +SFX B y ied y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic b/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic new file mode 100644 index 000000000..e228043ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.dic @@ -0,0 +1,4 @@ +3 +hello +try/B +work/AB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.good b/extensions/spellcheck/hunspell/tests/unit/data/affixes.good new file mode 100644 index 000000000..20097e8e6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.good @@ -0,0 +1,7 @@ +hello +try +tried +work +worked +rework +reworked diff --git a/extensions/spellcheck/hunspell/tests/unit/data/affixes.test b/extensions/spellcheck/hunspell/tests/unit/data/affixes.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/affixes.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias.aff new file mode 100644 index 000000000..3fbce0ac4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.aff @@ -0,0 +1,12 @@ +# aliases for flag vectors (AF) +# AB -> 1 +# A -> 2 +AF 2 +AF AB +AF A + +SFX A Y 1 +SFX A 0 x . + +SFX B Y 1 +SFX B 0 y/2 . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias.dic new file mode 100644 index 000000000..e0af3c918 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.dic @@ -0,0 +1,2 @@ +1 +foo/1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.good b/extensions/spellcheck/hunspell/tests/unit/data/alias.good new file mode 100644 index 000000000..71702f231 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.good @@ -0,0 +1,4 @@ +foo +foox +fooy +fooyx diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias.test b/extensions/spellcheck/hunspell/tests/unit/data/alias.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff new file mode 100644 index 000000000..66a183833 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.aff @@ -0,0 +1,17 @@ +# aliases for flag vectors (AF) and morphological descriptions (AM) +# AB -> 1 +# A -> 2 +AF 2 +AF AB +AF A + +AM 3 +AM is:affix_x +AM ds:affix_y +AM po:noun xx:other_data + +SFX A Y 1 +SFX A 0 x . 1 + +SFX B Y 1 +SFX B 0 y/2 . 2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic new file mode 100644 index 000000000..60300acee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.dic @@ -0,0 +1,2 @@ +1 +foo/1 3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.good b/extensions/spellcheck/hunspell/tests/unit/data/alias2.good new file mode 100644 index 000000000..71702f231 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.good @@ -0,0 +1,4 @@ +foo +foox +fooy +fooyx diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph b/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph new file mode 100644 index 000000000..01f983d57 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.morph @@ -0,0 +1,12 @@ +> foo +analyze(foo) = st:foo po:noun xx:other_data +stem(foo) = foo +> foox +analyze(foox) = st:foo po:noun xx:other_data is:affix_x +stem(foox) = foo +> fooy +analyze(fooy) = st:foo po:noun xx:other_data ds:affix_y +stem(fooy) = fooy +> fooyx +analyze(fooyx) = st:foo po:noun xx:other_data ds:affix_y is:affix_x +stem(fooyx) = fooy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias2.test b/extensions/spellcheck/hunspell/tests/unit/data/alias2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff b/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff new file mode 100644 index 000000000..a32818500 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.aff @@ -0,0 +1,18 @@ +# morph. aliases with complex prefixes +COMPLEXPREFIXES +WORDCHARS _ + +AM 4 +AM affix_1/ +AM affix_2/ +AM /suffix_1 +AM [stem_1] + +PFX A Y 1 +PFX A 0 tek . 1 + +PFX B Y 1 +PFX B 0 met/A . 2 + +SFX C Y 1 +SFX C 0 _test_ . 3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic b/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic new file mode 100644 index 000000000..f22567cbe --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.dic @@ -0,0 +1,2 @@ +1 +ouro/BC 4 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.good b/extensions/spellcheck/hunspell/tests/unit/data/alias3.good new file mode 100644 index 000000000..6bf822826 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.good @@ -0,0 +1,4 @@ +ouro +metouro +tekmetouro +ouro_test_ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph b/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph new file mode 100644 index 000000000..33edf5cee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.morph @@ -0,0 +1,8 @@ +> ouro +analyze(ouro) = [stem_1] ouro:ts +> metouro +analyze(metouro) = affix_2/ ouro:ts [stem_1] +> tekmetouro +analyze(tekmetouro) = affix_1/ affix_2/ ouro:ts [stem_1] +> ouro_test_ +analyze(ouro_test_) = [stem_1] ouro:ts /suffix_1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/alias3.test b/extensions/spellcheck/hunspell/tests/unit/data/alias3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/alias3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff new file mode 100644 index 000000000..a11762568 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.aff @@ -0,0 +1,6 @@ +SET UTF-8 +WORDCHARS '. + +SFX S N 1 +SFX S 0 's . + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic new file mode 100644 index 000000000..7d3cdcc04 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.dic @@ -0,0 +1,3 @@ +2 +OpenOffice.org +UNICEF/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good new file mode 100644 index 000000000..3afd877d9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.good @@ -0,0 +1,4 @@ +OpenOffice.org +OPENOFFICE.ORG +UNICEF's +UNICEF'S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug new file mode 100644 index 000000000..d372ff23d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.sug @@ -0,0 +1,3 @@ +OpenOffice.org +UNICEF +UNICEF's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong new file mode 100644 index 000000000..668194906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps-utf.wrong @@ -0,0 +1,3 @@ +Openoffice.org +Unicef +Unicef's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff new file mode 100644 index 000000000..57e916bf5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.aff @@ -0,0 +1,5 @@ +# check uppercase forms of allcaps word + affix and words with mixed casing +WORDCHARS '. + +SFX S N 1 +SFX S 0 's . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic new file mode 100644 index 000000000..7d3cdcc04 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.dic @@ -0,0 +1,3 @@ +2 +OpenOffice.org +UNICEF/S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good new file mode 100644 index 000000000..3afd877d9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.good @@ -0,0 +1,4 @@ +OpenOffice.org +OPENOFFICE.ORG +UNICEF's +UNICEF'S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug new file mode 100644 index 000000000..d372ff23d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.sug @@ -0,0 +1,3 @@ +OpenOffice.org +UNICEF +UNICEF's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong new file mode 100644 index 000000000..668194906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps.wrong @@ -0,0 +1,3 @@ +Openoffice.org +Unicef +Unicef's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff new file mode 100644 index 000000000..67022d6eb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.aff @@ -0,0 +1,6 @@ +# forbidden all caps words are case sensitive +# iPod -> ipodos ("iPodic" in Hungarian) +FORBIDDENWORD * +SFX s N 1 +SFX s 0 os . + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic new file mode 100644 index 000000000..be21bfb40 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.dic @@ -0,0 +1,4 @@ +3 +iPod/s +iPodos/* +ipodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good new file mode 100644 index 000000000..5fd2f82ce --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.good @@ -0,0 +1,4 @@ +iPod +IPOD +ipodos +IPODOS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug new file mode 100644 index 000000000..5c312d7b5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.sug @@ -0,0 +1,2 @@ +iPod +ipodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong new file mode 100644 index 000000000..010967be6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps2.wrong @@ -0,0 +1,2 @@ +ipod +iPodos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff new file mode 100644 index 000000000..789818e1a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.aff @@ -0,0 +1,10 @@ +# homonym support +WORDCHARS ' + +SFX s N 1 +SFX s 0 s . + +SFX S N 1 +SFX S 0 's . + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic new file mode 100644 index 000000000..e903a0fa9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.dic @@ -0,0 +1,7 @@ +4 +UNESCO/S +Unesco/S +Nasa/S +NASA/S +ACTS +act/s diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good new file mode 100644 index 000000000..b9930a24d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.good @@ -0,0 +1,13 @@ +UNESCO +Unesco +UNESCO's +Unesco's +UNESCO'S +NASA +Nasa +NASA's +Nasa's +NASA'S +ACTS +acts +Acts diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong new file mode 100644 index 000000000..89172b824 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/allcaps3.wrong @@ -0,0 +1,4 @@ +unesco +unesco's +nasa +nasa's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff b/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff new file mode 100644 index 000000000..f8dd5cf24 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.aff @@ -0,0 +1,6 @@ +SET UTF-8 +TRY أ +IGNORE ٌٍَُِّْ + +PFX Aa Y 1 +PFX Aa 0 0/X0 أ[^ي] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic b/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic new file mode 100644 index 000000000..9a2035def --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.dic @@ -0,0 +1,2 @@ +1 +ب diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.test b/extensions/spellcheck/hunspell/tests/unit/data/arabic.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong b/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong new file mode 100644 index 000000000..9b566c364 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/arabic.wrong @@ -0,0 +1 @@ +ـ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff new file mode 100644 index 000000000..493157b30 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.aff @@ -0,0 +1,198 @@ +# OpenOffice.org’s en_US.aff file +# with Unicode apostrophe: ’ + +SET UTF-8 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' + +MAXNGRAMSUGS 1 +WORDCHARS .'’ + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion +McDonalds’sá/w +McDonald’sszá/g3) st:McDonaldâs po:noun_prs is:TRANS +McDonald’sszal/g4) st:McDonaldâs po:noun_prs is:INSTR +McDonald’ssal/w diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic new file mode 100644 index 000000000..b2b536d28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.dic @@ -0,0 +1,29 @@ +28 +created/U +create/XKVNGADS +imply/GNSDX +natural/PUY +like/USPBY +convey/BDGS +look/GZRDS +text +hello +said +sawyer +NASA +rotten +day +tomorrow +seven +FAQ/SM +can’t +doesn’t +etc +won’t +lip +text +horrifying +speech +suggest +uncreate/V +Hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good new file mode 100644 index 000000000..4c73e42b8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.good @@ -0,0 +1,27 @@ +created +uncreate +uncreated +imply +implied +unnatural +conveyed +sawyer +NASA +FAQs +can’t +doesn’t +won’t +Created +Hello +HELLO +NASA +etc. +etc +HELLO +lip. +text. +NASA. +Text. +TEXT. +Hunspell. +HUNSPELL. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug new file mode 100644 index 000000000..990b640cf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.sug @@ -0,0 +1,11 @@ +looked, look +text, create +hello +said +rotten day, rotten-day, rotten +tomorrow, rotten +seven +NASA +horrifying +speech, Hunspell +suggest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong new file mode 100644 index 000000000..88a6e2520 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base-utf.wrong @@ -0,0 +1,11 @@ +loooked +texxt +hlelo +seid +rottenday +tomorow +seeeven +Nasa +horrorfying +peech +sugesst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.aff b/extensions/spellcheck/hunspell/tests/unit/data/base.aff new file mode 100644 index 000000000..632f04b96 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.aff @@ -0,0 +1,192 @@ +# OpenOffice.org's en_US.aff file + +SET ISO8859-1 +TRY esianrtolcdugmphbyfvkwz' + +WORDCHARS .' + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.dic b/extensions/spellcheck/hunspell/tests/unit/data/base.dic new file mode 100644 index 000000000..5d9b8a28b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.dic @@ -0,0 +1,29 @@ +28 +created/U +create/XKVNGADS +imply/GNSDX +natural/PUY +like/USPBY +convey/BDGS +look/GZRDS +text +hello +said +sawyer +NASA +rotten +day +tomorrow +seven +FAQ/SM +can't +doesn't +etc +won't +lip +text +horrifying +speech +suggest +uncreate/V +Hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.good b/extensions/spellcheck/hunspell/tests/unit/data/base.good new file mode 100644 index 000000000..8e7f88e2b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.good @@ -0,0 +1,27 @@ +created +uncreate +uncreated +imply +implied +unnatural +conveyed +sawyer +NASA +FAQs +can't +doesn't +won't +Created +Hello +HELLO +NASA +etc. +etc +HELLO +lip. +text. +NASA. +Text. +TEXT. +Hunspell. +HUNSPELL. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.sug b/extensions/spellcheck/hunspell/tests/unit/data/base.sug new file mode 100644 index 000000000..553280a6a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.sug @@ -0,0 +1,11 @@ +looked, look +text +hello +said +rotten day, rotten-day, rotten +tomorrow +seven +NASA +horrifying +speech +suggest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.test b/extensions/spellcheck/hunspell/tests/unit/data/base.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/base.wrong b/extensions/spellcheck/hunspell/tests/unit/data/base.wrong new file mode 100644 index 000000000..88a6e2520 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/base.wrong @@ -0,0 +1,11 @@ +loooked +texxt +hlelo +seid +rottenday +tomorow +seeeven +Nasa +horrorfying +peech +sugesst diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.aff b/extensions/spellcheck/hunspell/tests/unit/data/break.aff new file mode 100644 index 000000000..47b8f6b7b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.aff @@ -0,0 +1,8 @@ +# word break points test, recursive break at dash and n-dash +SET UTF-8 + +BREAK 2 +BREAK - +BREAK – + +WORDCHARS -– diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.dic b/extensions/spellcheck/hunspell/tests/unit/data/break.dic new file mode 100644 index 000000000..f3d2aa02f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.dic @@ -0,0 +1,4 @@ +3 +foo +bar +fox-bax diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.good b/extensions/spellcheck/hunspell/tests/unit/data/break.good new file mode 100644 index 000000000..5f08bfd2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.good @@ -0,0 +1,7 @@ +foo +bar +fox-bax +foo-bar +foo–bar +foo-bar-foo-bar +foo-bar–foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.test b/extensions/spellcheck/hunspell/tests/unit/data/break.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/break.wrong b/extensions/spellcheck/hunspell/tests/unit/data/break.wrong new file mode 100644 index 000000000..599ed9f7f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/break.wrong @@ -0,0 +1,12 @@ +fox +bax +-foo +bar- +fox-bar +foo-bax +foo–bax +fox–bar +foo-bar-fox-bar +foo-bax-foo-bar +foo-bar–fox-bar +foo-bax–foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff new file mode 100644 index 000000000..a13f464a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.aff @@ -0,0 +1,6 @@ +# default word break at hyphens and n-dashes + +SET UTF-8 +MAXNGRAMSUGS 0 +WORDCHARS - +TRY ot diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic new file mode 100644 index 000000000..bf2996035 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.dic @@ -0,0 +1,6 @@ +3 +foo +bar +free +scott +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good new file mode 100644 index 000000000..8d8125457 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.good @@ -0,0 +1,7 @@ +foo +bar +foo- +-foo +scot-free +foo-bar +foo-bar-foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug new file mode 100644 index 000000000..8bfc69d93 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.sug @@ -0,0 +1,3 @@ +scott +scot-free +foo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong new file mode 100644 index 000000000..c3b203a7f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakdefault.wrong @@ -0,0 +1,3 @@ +scot +sco-free +fo-bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff new file mode 100644 index 000000000..2e83d3802 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.aff @@ -0,0 +1,7 @@ +# switch off default word break at hyphens and n-dashes by BREAK 0 +SET UTF-8 +MAXNGRAMSUGS 0 +WORDCHARS - +TRY ot + +BREAK 0 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic new file mode 100644 index 000000000..bf2996035 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.dic @@ -0,0 +1,6 @@ +3 +foo +bar +free +scott +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good new file mode 100644 index 000000000..854b39efa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.good @@ -0,0 +1,3 @@ +foo +bar +scot-free diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong new file mode 100644 index 000000000..a6fcf7f1e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/breakoff.wrong @@ -0,0 +1,5 @@ +foo- +-foo +foo-bar +foo-bar-foo-bar +scot diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff new file mode 100644 index 000000000..7ac46eeab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.aff @@ -0,0 +1,3 @@ +# forbid upper case letters at word bounds in compounding +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic new file mode 100644 index 000000000..80f65d38f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.dic @@ -0,0 +1,5 @@ +4 +foo/A +Bar/A +BAZ/A +-/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good new file mode 100644 index 000000000..9cbd79064 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.good @@ -0,0 +1,5 @@ +Barfoo +foo-Bar +foo-BAZ +BAZ-foo +BAZ-Bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong new file mode 100644 index 000000000..0714c22e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase.wrong @@ -0,0 +1,3 @@ +fooBar +BAZBar +BAZfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff new file mode 100644 index 000000000..fea046b19 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.aff @@ -0,0 +1,3 @@ +# check extended ascii +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic new file mode 100644 index 000000000..086de0aed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.dic @@ -0,0 +1,3 @@ +2 +o/A +o/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good new file mode 100644 index 000000000..b38fd0c6c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.good @@ -0,0 +1,2 @@ +oo +oo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong new file mode 100644 index 000000000..94786e95b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcase2.wrong @@ -0,0 +1 @@ +oo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff new file mode 100644 index 000000000..546f478a5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.aff @@ -0,0 +1,3 @@ +SET UTF-8 +CHECKCOMPOUNDCASE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic new file mode 100644 index 000000000..0b7fbc9ac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.dic @@ -0,0 +1,3 @@ +2 +áoó/A +Óoá/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good new file mode 100644 index 000000000..32ae1353c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.good @@ -0,0 +1,2 @@ +áoóáoó +Óoááoó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong new file mode 100644 index 000000000..07434ccae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundcaseutf.wrong @@ -0,0 +1 @@ +áoóÓoá diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff new file mode 100644 index 000000000..5cd357a5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.aff @@ -0,0 +1,3 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDDUP +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic new file mode 100644 index 000000000..8ac75f4fc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.dic @@ -0,0 +1,3 @@ +2 +foo/A +bar/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good new file mode 100644 index 000000000..3866f24ca --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.good @@ -0,0 +1,5 @@ +barfoo +foobar +foofoobar +foobarfoo +barfoobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong new file mode 100644 index 000000000..5e809b3d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompounddup.wrong @@ -0,0 +1,3 @@ +foofoo +foofoofoo +foobarbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff new file mode 100644 index 000000000..dfda51af2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.aff @@ -0,0 +1,5 @@ +# forbid compounds with spec. pattern at word bounds +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN nny ny +CHECKCOMPOUNDPATTERN ssz sz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic new file mode 100644 index 000000000..09300f0bc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.dic @@ -0,0 +1,5 @@ +4 +knny/A +nyels/A +hossz/A +szmts/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good new file mode 100644 index 000000000..0f99c52d2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.good @@ -0,0 +1,2 @@ +knnyszmts +hossznyels diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong new file mode 100644 index 000000000..5edd11534 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern.wrong @@ -0,0 +1,4 @@ +knnynyels +hosszszmts +hosszknnynyels +knnynyelshossz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff new file mode 100644 index 000000000..fdf6560b4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.aff @@ -0,0 +1,7 @@ +# forbid compounds with spec. pattern at word bound and allow modificated form +# (for German and Indian languages) +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN o b z +CHECKCOMPOUNDPATTERN oo ba u +COMPOUNDMIN 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic new file mode 100644 index 000000000..8ac75f4fc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.dic @@ -0,0 +1,3 @@ +2 +foo/A +bar/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good new file mode 100644 index 000000000..eaad4f902 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.good @@ -0,0 +1,3 @@ +barfoo +fozar +fur diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong new file mode 100644 index 000000000..323fae03f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern2.wrong @@ -0,0 +1 @@ +foobar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff new file mode 100644 index 000000000..6c2cfa4aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.aff @@ -0,0 +1,6 @@ +# forbid compounds with spec. pattern at word bound and allow modificated form +# (for Indian languages) +COMPOUNDFLAG A +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN o/X b/Y z +COMPOUNDMIN 1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic new file mode 100644 index 000000000..6bd1b7fc9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.dic @@ -0,0 +1,5 @@ +4 +foo/A +boo/AX +bar/A +ban/AY diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good new file mode 100644 index 000000000..6070eff5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.good @@ -0,0 +1,9 @@ +bozan +barfoo +banfoo +banbar +foobar +fooban +foobanbar +boobar +boobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong new file mode 100644 index 000000000..41d8d3747 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern3.wrong @@ -0,0 +1,8 @@ +booban +boobanfoo +fozar +fozarfoo +fozan +fozanfoo +bozar +bozarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff new file mode 100644 index 000000000..ef2566308 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.aff @@ -0,0 +1,8 @@ +# sandhi in Telugu writing system, based on the Kiran Chittella's example + +COMPOUNDFLAG x +COMPOUNDMIN 1 +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN a/A u/A O +CHECKCOMPOUNDPATTERN u/B u/B u + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic new file mode 100644 index 000000000..d245ef019 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.dic @@ -0,0 +1,6 @@ +4 +sUrya/Ax +udayaM/Ax +pEru/Bx +unna/Bx + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good new file mode 100644 index 000000000..48761b6ee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.good @@ -0,0 +1,2 @@ +sUryOdayaM +pErunna diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong new file mode 100644 index 000000000..a357fec52 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundpattern4.wrong @@ -0,0 +1,2 @@ +sUryaudayaM +pEruunna diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff new file mode 100644 index 000000000..4fb7ff55e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.aff @@ -0,0 +1,8 @@ +// forbid compound word, if it is also a non compound word with a REP fault +// In example: Hungarian `szervz' (szer+vz) compound word is forbidden, because +// this word is also a dictionary word (szerviz) with typical fault (i->) +CHECKCOMPOUNDREP +COMPOUNDFLAG A + +REP 1 +REP i diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic new file mode 100644 index 000000000..030bda916 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.dic @@ -0,0 +1,5 @@ +3 +szer/A +vz/A +szerviz +kocsi/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good new file mode 100644 index 000000000..c95c03c87 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.good @@ -0,0 +1,2 @@ +vzszer +szerkocsi
\ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong new file mode 100644 index 000000000..8c8701d47 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundrep.wrong @@ -0,0 +1,3 @@ +szervz +szervzkocsi +kocsiszervz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff new file mode 100644 index 000000000..7159cf55d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.aff @@ -0,0 +1,3 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDTRIPLE +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic new file mode 100644 index 000000000..607c489e8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.dic @@ -0,0 +1,5 @@ +4 +foo/A +opera/A +eel/A +bare/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good new file mode 100644 index 000000000..1293f749a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.good @@ -0,0 +1,6 @@ +operafoo +operaeel +operabare +eelbare +eelfoo +eelopera diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong new file mode 100644 index 000000000..ae2d02b20 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checkcompoundtriple.wrong @@ -0,0 +1,2 @@ +fooopera +bareeel diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff new file mode 100644 index 000000000..6b22c7390 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.aff @@ -0,0 +1,4 @@ +# test - SS special capitalizing +CHECKSHARPS +WORDCHARS . +KEEPCASE k diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic new file mode 100644 index 000000000..91d14ab9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.dic @@ -0,0 +1,7 @@ +6 +mig/k +Aussto +Absto. +Auenabmessung +Prozessionsstrae +Auenmae diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good new file mode 100644 index 000000000..e9be8c5c7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.good @@ -0,0 +1,13 @@ +mig +Mig +MSSIG +Aussto +Absto. +Auenabmessung +Prozessionsstrae +Auenmae +AUSSTOSS +ABSTOSS. +AUSSENABMESSUNG +PROZESSIONSSTRASSE +AUSSENMASSE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug new file mode 100644 index 000000000..52c6a943b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.sug @@ -0,0 +1 @@ +MSSIG, mig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong new file mode 100644 index 000000000..96eb8aea7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharps.wrong @@ -0,0 +1 @@ +MIG diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff new file mode 100644 index 000000000..86c0fc426 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.aff @@ -0,0 +1,5 @@ +# test - SS special capitalizing in UTF-8 +SET UTF-8 +CHECKSHARPS +WORDCHARS ß. +KEEPCASE k diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic new file mode 100644 index 000000000..9cc364eec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.dic @@ -0,0 +1,7 @@ +6 +müßig/k +Ausstoß +Abstoß. +Außenabmessung +Prozessionsstraße +Außenmaße diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good new file mode 100644 index 000000000..a61c24319 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.good @@ -0,0 +1,13 @@ +müßig +Müßig +MÜSSIG +Ausstoß +Abstoß. +Außenabmessung +Prozessionsstraße +Außenmaße +AUSSTOSS +ABSTOSS. +AUSSENABMESSUNG +PROZESSIONSSTRASSE +AUSSENMASSE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug new file mode 100644 index 000000000..ab68568e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.sug @@ -0,0 +1 @@ +MÜSSIG, müßig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong new file mode 100644 index 000000000..25eb03dce --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/checksharpsutf.wrong @@ -0,0 +1 @@ +MÜßIG diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff new file mode 100644 index 000000000..1eecc644b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.aff @@ -0,0 +1,16 @@ +# circumfixes: ~ obligate prefix/suffix combinations +# superlative in Hungarian: leg- (prefix) AND -bb (suffix) + +CIRCUMFIX X + +PFX A Y 1 +PFX A 0 leg/X . + +PFX B Y 1 +PFX B 0 legesleg/X . + +SFX C Y 3 +SFX C 0 obb . is:COMPARATIVE +SFX C 0 obb/AX . is:SUPERLATIVE +SFX C 0 obb/BX . is:SUPERSUPERLATIVE + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic new file mode 100644 index 000000000..ba96f046d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.dic @@ -0,0 +1,2 @@ +1 +nagy/C po:adj diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good new file mode 100644 index 000000000..65049d9f0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.good @@ -0,0 +1,4 @@ +nagy +nagyobb +legnagyobb +legeslegnagyobb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph new file mode 100644 index 000000000..62e6c5371 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.morph @@ -0,0 +1,12 @@ +> nagy +analyze(nagy) = st:nagy po:adj +stem(nagy) = nagy +> nagyobb +analyze(nagyobb) = st:nagy po:adj is:COMPARATIVE +stem(nagyobb) = nagy +> legnagyobb +analyze(legnagyobb) = fl:A st:nagy po:adj is:SUPERLATIVE +stem(legnagyobb) = nagy +> legeslegnagyobb +analyze(legeslegnagyobb) = fl:B st:nagy po:adj is:SUPERSUPERLATIVE +stem(legeslegnagyobb) = nagy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong new file mode 100644 index 000000000..bab8084ee --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/circumfix.wrong @@ -0,0 +1,2 @@ +legnagy +legeslegnagy diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff new file mode 100644 index 000000000..d08022694 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.aff @@ -0,0 +1,3 @@ +# Colons in Finnish and Swedish words. Problem reported by Lars Aronsson. +# Parsing test (src/parsers) +WORDCHARS : diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic new file mode 100644 index 000000000..bfea1ccc7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.dic @@ -0,0 +1,4 @@ +2 +c:a +S:t +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/colons-in-words.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff new file mode 100644 index 000000000..7ddb497a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.aff @@ -0,0 +1,9 @@ +# set twofold prefix stripping +# Coptic example by Moheb Mekhaiel +COMPLEXPREFIXES + +PFX A Y 1 +PFX A 0 tek . + +PFX B Y 1 +PFX B 0 met/A . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic new file mode 100644 index 000000000..2618c7cf4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.dic @@ -0,0 +1,3 @@ +1 +ouro/B + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good new file mode 100644 index 000000000..eed87a774 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.good @@ -0,0 +1,3 @@ +ouro +metouro +tekmetouro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong new file mode 100644 index 000000000..fb1c8b483 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes.wrong @@ -0,0 +1,2 @@ +tekouro +mettekouro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff new file mode 100644 index 000000000..b4fe1dca6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.aff @@ -0,0 +1,12 @@ +# complex prefixes with morphological analysis +COMPLEXPREFIXES +WORDCHARS _ + +PFX A Y 1 +PFX A 0 tek . affix_1/ + +PFX B Y 1 +PFX B 0 met/A . affix_2/ + +SFX C Y 1 +SFX C 0 _test_ . /suffix_1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic new file mode 100644 index 000000000..7e4baf06c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.dic @@ -0,0 +1,3 @@ +1 +ouro/BC [stem_1] + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good new file mode 100644 index 000000000..6bf822826 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.good @@ -0,0 +1,4 @@ +ouro +metouro +tekmetouro +ouro_test_ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixes2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff new file mode 100644 index 000000000..3991e9f5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.aff @@ -0,0 +1,12 @@ +# Coptic example by Moheb Mekhaiel +# Encoded with the new Coptic character encoding of Unicode 4.1 +SET UTF-8 + +# set twofold prefix stripping +COMPLEXPREFIXES + +PFX A Y 1 +PFX A 0 ⲧⲉⲕ . + +PFX B Y 1 +PFX B 0 ⲙⲉⲧ/A . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic new file mode 100644 index 000000000..bd0eb6df0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.dic @@ -0,0 +1,2 @@ +1 +ⲟⲩⲣⲟ/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good new file mode 100644 index 000000000..7eb956619 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.good @@ -0,0 +1,3 @@ +ⲟⲩⲣⲟ +ⲙⲉⲧⲟⲩⲣⲟ +ⲧⲉⲕⲙⲉⲧⲟⲩⲣⲟ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong new file mode 100644 index 000000000..d8021fc44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/complexprefixesutf.wrong @@ -0,0 +1,2 @@ +ⲧⲉⲕⲟⲩⲣⲟ +ⲙⲉⲧⲧⲉⲕⲟⲩⲣⲟ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff new file mode 100644 index 000000000..cae5669c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.aff @@ -0,0 +1,7 @@ +COMPOUNDFLAG X + +PFX P Y 1 +PFX P 0 pre . + +SFX S Y 1 +SFX S 0 suf . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good new file mode 100644 index 000000000..af1f0019a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.good @@ -0,0 +1,6 @@ +foo +foofoo +prefoo +foosuf +prefoosuf +prefoobarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong new file mode 100644 index 000000000..b7e4067bc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix.wrong @@ -0,0 +1,3 @@ +foosufbar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff new file mode 100644 index 000000000..1cac16e11 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.aff @@ -0,0 +1,8 @@ +COMPOUNDFLAG X +COMPOUNDPERMITFLAG Y + +PFX P Y 1 +PFX P 0 pre/Y . + +SFX S Y 1 +SFX S 0 suf/Y . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good new file mode 100644 index 000000000..9f3020da0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.good @@ -0,0 +1,8 @@ +foo +prefoo +foosuf +prefoosuf +prefoobarsuf +foosufbar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff new file mode 100644 index 000000000..98a12b56c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.aff @@ -0,0 +1,8 @@ +COMPOUNDFLAG X +COMPOUNDFORBIDFLAG Z + +PFX P Y 1 +PFX P 0 pre/Z . + +SFX S Y 1 +SFX S 0 suf/Z . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic new file mode 100644 index 000000000..eba6b83fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.dic @@ -0,0 +1,3 @@ +2 +foo/XPS +bar/XPS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good new file mode 100644 index 000000000..76cc08eae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.good @@ -0,0 +1,5 @@ +foo +foofoo +prefoo +foosuf +prefoosuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong new file mode 100644 index 000000000..d92b90b28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundaffix3.wrong @@ -0,0 +1,6 @@ +prefoobarsuf +foosufbar +fooprebar +foosufprebar +fooprebarsuf +prefooprebarsuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff new file mode 100644 index 000000000..bc8369ceb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 3 +COMPOUNDFLAG A + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic new file mode 100644 index 000000000..d1ea8e96e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.dic @@ -0,0 +1,5 @@ +4 +foo/A +bar/A +xy/A +yz/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good new file mode 100644 index 000000000..21cc29f2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.good @@ -0,0 +1,3 @@ +foobar +barfoo +foobarfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong new file mode 100644 index 000000000..c185bf150 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundflag.wrong @@ -0,0 +1,4 @@ +xyyz +fooxy +xyfoo +fooxybar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff new file mode 100644 index 000000000..09309e0aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE ABC diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic new file mode 100644 index 000000000..b11e8291e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/BC + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good new file mode 100644 index 000000000..c7a0763bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.good @@ -0,0 +1,2 @@ +abc +acc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong new file mode 100644 index 000000000..bc151ea02 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule.wrong @@ -0,0 +1,39 @@ +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +aa +aaa +aaaa +ab +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +ac +aac +aacc +aaaccc +bc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff new file mode 100644 index 000000000..e4b86a53b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE A*B*C* diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good new file mode 100644 index 000000000..de743bb06 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.good @@ -0,0 +1,37 @@ +aa +aaa +aaaa +ab +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abc +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +ac +acc +aac +aacc +aaaccc +bc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc +abcc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong new file mode 100644 index 000000000..9e5d38d35 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule2.wrong @@ -0,0 +1,8 @@ +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +cba +cab +acb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff new file mode 100644 index 000000000..005314586 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.aff @@ -0,0 +1,3 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 1 +COMPOUNDRULE A?B?C? diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good new file mode 100644 index 000000000..7f518893e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.good @@ -0,0 +1,7 @@ +a +b +c +ab +abc +ac +bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong new file mode 100644 index 000000000..6bd1d8004 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule3.wrong @@ -0,0 +1,41 @@ +aa +aaa +aaaa +aab +aaab +aaaab +abb +aabb +aaabbb +bb +bbb +bbbb +aaab +abcc +abbc +abbcc +aabc +aabcc +aabbc +aabbcc +aaabbbccc +acc +aac +aacc +aaaccc +bcc +bbc +bbcc +bbbccc +cc +ccc +cccccc +abcc +ba +aaabaaa +bbaaa +aaaaba +bbbbbaa +cba +cab +acb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff new file mode 100644 index 000000000..8a9996cb3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.aff @@ -0,0 +1,7 @@ +# English ordinal numbers +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND c +COMPOUNDRULE 2 +COMPOUNDRULE n*1t +COMPOUNDRULE n*mp diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic new file mode 100644 index 000000000..ced0735ec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.dic @@ -0,0 +1,24 @@ +22 +0/nm +1/n1 +2/nm +3/nm +4/nm +5/nm +6/nm +7/nm +8/nm +9/nm +0th/pt +1st/p +1th/tc +2nd/p +2th/tc +3rd/p +3th/tc +4th/pt +5th/pt +6th/pt +7th/pt +8th/pt +9th/pt diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule4.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff new file mode 100644 index 000000000..46502460b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.aff @@ -0,0 +1,7 @@ +# number + percent +SET UTF-8 +COMPOUNDMIN 1 +COMPOUNDRULE 2 +COMPOUNDRULE N*%? +COMPOUNDRULE NN*.NN*%? +WORDCHARS 0123456789‰. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic new file mode 100644 index 000000000..eeeffdac5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.dic @@ -0,0 +1,14 @@ +13 +0/N po:num +1/N po:num +2/N po:num +3/N po:num +4/N po:num +5/N po:num +6/N po:num +7/N po:num +8/N po:num +9/N po:num +./. po:sign_dot +%/% po:sign_percent +‰/% po:sign_per_mille diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good new file mode 100644 index 000000000..691fca1fb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.good @@ -0,0 +1,7 @@ +10% +0.2% +0.20% +123.4561‰ +10 +0000 +10.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph new file mode 100644 index 000000000..107a80859 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.morph @@ -0,0 +1,21 @@ +> 10% +analyze(10%) = pa:1 st:1 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent +stem(10%) = 10% +> 0.2% +analyze(0.2%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:% st:% po:sign_percent +stem(0.2%) = 0.2% +> 0.20% +analyze(0.20%) = pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:0 st:0 po:num pa:% st:% po:sign_percent +stem(0.20%) = 0.20% +> 123.4561‰ +analyze(123.4561‰) = pa:1 st:1 po:num pa:2 st:2 po:num pa:3 st:3 po:num pa:. st:. po:sign_dot pa:4 st:4 po:num pa:5 st:5 po:num pa:6 st:6 po:num pa:1 st:1 po:num pa:‰ st:‰ po:sign_per_mille +stem(123.4561‰) = 123.4561‰ +> 10 +analyze(10) = pa:1 st:1 po:num pa:0 st:0 po:num +stem(10) = 10 +> 0000 +analyze(0000) = pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num pa:0 st:0 po:num +stem(0000) = 0000 +> 10.25 +analyze(10.25) = pa:1 st:1 po:num pa:0 st:0 po:num pa:. st:. po:sign_dot pa:2 st:2 po:num pa:5 st:5 po:num +stem(10.25) = 10.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong new file mode 100644 index 000000000..ba1fe3290 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule5.wrong @@ -0,0 +1 @@ +.25 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff new file mode 100644 index 000000000..e8a088d5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.aff @@ -0,0 +1,4 @@ +COMPOUNDMIN 1 +COMPOUNDRULE 2 +COMPOUNDRULE A*A +COMPOUNDRULE A*AAB*BBBC*C diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic new file mode 100644 index 000000000..7d07bbc89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.dic @@ -0,0 +1,5 @@ +3 +a/A +b/B +c/C + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good new file mode 100644 index 000000000..55a8f8bc5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.good @@ -0,0 +1,4 @@ +aa +aaaaaa +aabbbc +aaaaabbbbbbcccccc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong new file mode 100644 index 000000000..48b376dac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule6.wrong @@ -0,0 +1,4 @@ +abc +abbbbbccccccc +aabbccccccc +aabbbbbbb diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff new file mode 100644 index 000000000..3ae1fc784 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.aff @@ -0,0 +1,8 @@ +# English ordinal numbers (parenthesized long flags) +FLAG long +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND cc +COMPOUNDRULE 2 +COMPOUNDRULE (nn)*(11)(tt) +COMPOUNDRULE (nn)*(mm)(pp) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic new file mode 100644 index 000000000..ad4bb4d28 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.dic @@ -0,0 +1,24 @@ +22 +0/nnmm +1/nn11 +2/nnmm +3/nnmm +4/nnmm +5/nnmm +6/nnmm +7/nnmm +8/nnmm +9/nnmm +0th/pptt +1st/pp +1th/ttcc +2nd/pp +2th/ttcc +3rd/pp +3th/ttcc +4th/pptt +5th/pptt +6th/pptt +7th/pptt +8th/pptt +9th/pptt diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule7.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff new file mode 100644 index 000000000..03a423d48 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.aff @@ -0,0 +1,8 @@ +# English ordinal numbers (parenthesized numerical flags) +FLAG num +WORDCHARS 0123456789 +COMPOUNDMIN 1 +ONLYINCOMPOUND 1000 +COMPOUNDRULE 2 +COMPOUNDRULE (1001)*(1002)(2001) +COMPOUNDRULE (1001)*(2002)(2000) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic new file mode 100644 index 000000000..e156e95fe --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.dic @@ -0,0 +1,24 @@ +22 +0/1001,2002 +1/1001,1002 +2/1001,2002 +3/1001,2002 +4/1001,2002 +5/1001,2002 +6/1001,2002 +7/1001,2002 +8/1001,2002 +9/1001,2002 +0th/2000,2001 +1st/2000 +1th/2001,1000 +2nd/2000 +2th/2001,1000 +3rd/2000 +3th/2001,1000 +4th/2000,2001 +5th/2000,2001 +6th/2000,2001 +7th/2000,2001 +8th/2000,2001 +9th/2000,2001 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good new file mode 100644 index 000000000..fafe64a5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.good @@ -0,0 +1,29 @@ +1st +2nd +3rd +4th +5th +6th +7th +8th +9th +10th +11th +12th +13th +14th +15th +16th +17th +18th +19th +20th +21st +22nd +23rd +24th +25th +100th +1000th +10001st +10011th diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test new file mode 100644 index 000000000..52e144cb8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.test @@ -0,0 +1,6 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong new file mode 100644 index 000000000..99f28e7cc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/compoundrule8.wrong @@ -0,0 +1,5 @@ +1th +2th +3th +10001th +10011st diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff new file mode 100644 index 000000000..62a1ce5e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.aff @@ -0,0 +1,42 @@ +SET UTF-8 +WORDCHARS 0123456789 + +SFX S N 18 +SFX S 0 suf1 . +SFX S 0 suf2 ó +SFX S 0 suf3 [áéóú] +SFX S 0 suf4 [^ó] +SFX S 0 suf5 [^áéóú] +SFX S 0 suf6 őó +SFX S 0 suf7 ő[áéóú] +SFX S 0 suf8 ő[^ó] +SFX S 0 suf9 ő[^áéóú] +SFX S 0 suf10 [áéóőú]ó +SFX S 0 suf11 [^ő]ó +SFX S 0 suf12 [^áéóőú]ó +SFX S 0 suf13 [áéőú][^ú] +SFX S 0 suf14 [^ú][áéóú] +SFX S 0 suf15 [áéóú][^áéőú] +SFX S 0 suf16 [^áéóú][^áéőú] +SFX S 0 suf17 [áéóú][bcdfgkmnóprstvz] +SFX S 0 suf18 [áéóú]ó + +PFX P N 18 +PFX P 0 pre1 . +PFX P 0 pre2 ó +PFX P 0 pre3 [áéóú] +PFX P 0 pre4 [^ó] +PFX P 0 pre5 [^áéóú] +PFX P 0 pre6 óő +PFX P 0 pre7 ó[áéőú] +PFX P 0 pre8 ó[^ő] +PFX P 0 pre9 ó[^áéóőú] +PFX P 0 pre10 [áéóőú]ő +PFX P 0 pre11 [^ó]ő +PFX P 0 pre12 [^áéóőú]ő +PFX P 0 pre13 [áéóú][áéőú] +PFX P 0 pre14 [áéóú][^áéóú] +PFX P 0 pre15 [áéóú][^áéőú] +PFX P 0 pre16 [^áéőú][^áéóú] +PFX P 0 pre17 [bcdfgkmnóprstvz][áéóú] +PFX P 0 pre18 ó[áéóú] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic new file mode 100644 index 000000000..f03ce4ea2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.dic @@ -0,0 +1,2 @@ +1 +óőó/SP diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good new file mode 100644 index 000000000..6c6203737 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.good @@ -0,0 +1,19 @@ +óőó +óőósuf1 +pre1óőó +óőósuf2 +pre2óőó +óőósuf3 +pre3óőó +óőósuf6 +pre6óőó +óőósuf7 +pre7óőó +óőósuf10 +pre10óőó +óőósuf13 +pre13óőó +óőósuf14 +pre14óőó +óőósuf16 +pre16óőó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong new file mode 100644 index 000000000..f1022132c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition-utf.wrong @@ -0,0 +1,18 @@ +óőósuf4 +pre4óőó +óőósuf5 +pre5óőó +óőósuf8 +pre8óőó +óőósuf9 +pre9óőó +óőósuf11 +pre11óőó +óőósuf12 +pre12óőó +óőósuf15 +pre15óőó +óőósuf17 +óőósuf18 +pre17óőó +pre18óőó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.aff b/extensions/spellcheck/hunspell/tests/unit/data/condition.aff new file mode 100644 index 000000000..62157421a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.aff @@ -0,0 +1,62 @@ +SET ISO8859-2 +WORDCHARS 0123456789 + +SFX S N 18 +SFX S 0 suf1 . +SFX S 0 suf2 o +SFX S 0 suf3 [aeou] +SFX S 0 suf4 [^o] +SFX S 0 suf5 [^aeou] +SFX S 0 suf6 fo +SFX S 0 suf7 f[aeou] +SFX S 0 suf8 f[^o] +SFX S 0 suf9 f[^aeou] +SFX S 0 suf10 [aefu]o +SFX S 0 suf11 [^f]o +SFX S 0 suf12 [^aefu]o +SFX S 0 suf13 [aefu][^aefu] +SFX S 0 suf14 [^aeou][aeou] +SFX S 0 suf15 [aeou][^aefu] +SFX S 0 suf16 [^aeou][^aefu] +SFX S 0 suf17 [aeou][bcdfgkmnoprstvz] +SFX S 0 suf18 [aeou]o + +SFX Q N 2 +SFX Q 0 ning [^aeio][aeiou]n +SFX Q 0 ing [aeio][aeiou][bcdfgkmnprstvz] + +SFX T N 1 +SFX T y ies .[^aeiou]y + +PFX U N 1 +PFX U 0 un wr. + +SFX Z Y 3 +SFX Z 0 ch [].a +SFX Z 0 m [].a +SFX Z a 0 [].a + +PFX P N 18 +PFX P 0 pre1 . +PFX P 0 pre2 o +PFX P 0 pre3 [aeou] +PFX P 0 pre4 [^o] +PFX P 0 pre5 [^aeou] +PFX P 0 pre6 of +PFX P 0 pre7 o[aefou] +PFX P 0 pre8 o[^f] +PFX P 0 pre9 o[^aefu] +PFX P 0 pre10 [aefu]o +PFX P 0 pre11 [^f]o +PFX P 0 pre12 [^aefou]o +PFX P 0 pre13 [aeou][aefu] +PFX P 0 pre14 [aeou][^aeou] +PFX P 0 pre15 [aeou][^aefu] +PFX P 0 pre16 [^aefu][^aeou] +PFX P 0 pre17 [bcdfgkmnoprstvz][aeou] +PFX P 0 pre18 o[aeou] + + +PFX R N 2 +PFX R 0 gnin n[aeiou][^aeio] +PFX R 0 gni [bcdfgkmnprstvz][aeiou][aeio] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.dic b/extensions/spellcheck/hunspell/tests/unit/data/condition.dic new file mode 100644 index 000000000..40ebd5588 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.dic @@ -0,0 +1,6 @@ +5 +ofo/SP +entertain/Q +nianretne/R +ra/Z +wry/TU diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.good b/extensions/spellcheck/hunspell/tests/unit/data/condition.good new file mode 100644 index 000000000..8fef4a747 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.good @@ -0,0 +1,26 @@ +ofo +ofosuf1 +pre1ofo +ofosuf2 +pre2ofo +ofosuf3 +pre3ofo +ofosuf6 +pre6ofo +ofosuf7 +pre7ofo +ofosuf10 +ofosuf13 +pre13ofo +ofosuf14 +pre14ofo +ofosuf16 +pre16ofo +entertain +entertaining +gninianretne +r +ram +rach +wries +unwry diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.test b/extensions/spellcheck/hunspell/tests/unit/data/condition.test new file mode 100644 index 000000000..c95329532 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong b/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong new file mode 100644 index 000000000..7b83d828d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/condition.wrong @@ -0,0 +1,21 @@ +ofosuf4 +pre4ofo +ofosuf5 +pre5ofo +ofosuf8 +pre8ofo +ofosuf9 +pre9ofo +ofosuf11 +pre10ofo +pre11ofo +ofosuf12 +pre12ofo +ofosuf15 +pre15ofo +ofosuf17 +pre17ofo +ofosuf18 +pre18ofo +entertainning +gninnianretne diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff new file mode 100644 index 000000000..e7a9bf749 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.aff @@ -0,0 +1,11 @@ +PFX P Y 1 +PFX P 0 un . ip:un + +SFX S Y 1 +SFX S 0 s . is:PL + +SFX Q Y 1 +SFX Q 0 s . is:3SGV + +SFX R Y 1 +SFX R 0 able/PS . ds:DER_V_ADJ_ABLE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic new file mode 100644 index 000000000..2f6d45615 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.dic @@ -0,0 +1,3 @@ +2 +drink/RQ po:verb +drink/S po:noun diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good new file mode 100644 index 000000000..01438d0eb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.good @@ -0,0 +1,6 @@ +drink +drinks +drinkable +drinkables +undrinkable +undrinkables diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph new file mode 100644 index 000000000..95d544389 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.morph @@ -0,0 +1,20 @@ +> drink +analyze(drink) = st:drink po:verb +analyze(drink) = st:drink po:noun +stem(drink) = drink +> drinks +analyze(drinks) = st:drink po:verb is:3SGV +analyze(drinks) = st:drink po:noun is:PL +stem(drinks) = drink +> drinkable +analyze(drinkable) = st:drink po:verb ds:DER_V_ADJ_ABLE +stem(drinkable) = drinkable +> drinkables +analyze(drinkables) = st:drink po:verb ds:DER_V_ADJ_ABLE is:PL +stem(drinkables) = drinkable +> undrinkable +analyze(undrinkable) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE +stem(undrinkable) = drinkable +> undrinkables +analyze(undrinkables) = ip:un st:drink po:verb ds:DER_V_ADJ_ABLE is:PL +stem(undrinkables) = drinkable diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong new file mode 100644 index 000000000..70262d940 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/conditionalprefix.wrong @@ -0,0 +1,2 @@ +undrink +undrinks diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff new file mode 100644 index 000000000..18a42f6fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.aff @@ -0,0 +1,9 @@ +# Digits in words, handled by COMPOUNDRULE. +# 1-jährig, 2-jährig, 100-jährig etc. +SET UTF-8 +COMPOUNDMIN 1 +# recognize ab, aab, aaab etc. compounds (a=digits, b=-jährig, see dic file) +COMPOUNDRULE 1 +COMPOUNDRULE a*b +ONLYINCOMPOUND c +WORDCHARS 0123456789- diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic new file mode 100644 index 000000000..deeaece05 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.dic @@ -0,0 +1,12 @@ +11 +0/a +1/a +2/a +3/a +4/a +5/a +6/a +7/a +8/a +9/a +-jährig/bc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong new file mode 100644 index 000000000..aeaf6ce34 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/digits-in-words.wrong @@ -0,0 +1 @@ +-jährig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff b/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff new file mode 100644 index 000000000..1f560d262 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.aff @@ -0,0 +1 @@ +SET ISO-8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic b/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic new file mode 100644 index 000000000..414f9b8d3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.dic @@ -0,0 +1,3 @@ +2 +cur +uvre diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.good b/extensions/spellcheck/hunspell/tests/unit/data/encoding.good new file mode 100644 index 000000000..fc41c90aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.good @@ -0,0 +1,4 @@ +cur +uvre +CUR +UVRE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/encoding.test b/extensions/spellcheck/hunspell/tests/unit/data/encoding.test new file mode 100644 index 000000000..09619572e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/encoding.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.aff b/extensions/spellcheck/hunspell/tests/unit/data/flag.aff new file mode 100644 index 000000000..ac105c11f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.aff @@ -0,0 +1,13 @@ +# base 1-character flags + +SFX A Y 1 +SFX A 0 s/123 . + +SFX 1 Y 1 +SFX 1 0 bar . + +SFX 2 Y 1 +SFX 2 0 baz . + +PFX 3 Y 1 +PFX 3 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.dic b/extensions/spellcheck/hunspell/tests/unit/data/flag.dic new file mode 100644 index 000000000..b1b237106 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.dic @@ -0,0 +1,2 @@ +1 +foo/A3 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.good b/extensions/spellcheck/hunspell/tests/unit/data/flag.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flag.test b/extensions/spellcheck/hunspell/tests/unit/data/flag.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flag.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff new file mode 100644 index 000000000..437f13b3a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.aff @@ -0,0 +1,14 @@ +# 2-character flags +FLAG long + +SFX zx Y 1 +SFX zx 0 s/g?1G09 . + +SFX g? Y 1 +SFX g? 0 bar . + +SFX 1G Y 1 +SFX 1G 0 baz . + +PFX 09 Y 1 +PFX 09 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic new file mode 100644 index 000000000..46c601286 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.dic @@ -0,0 +1,2 @@ +1 +foo/zx09 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flaglong.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff new file mode 100644 index 000000000..823cee4cd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.aff @@ -0,0 +1,14 @@ +# numerical flags +FLAG num + +SFX 999 Y 1 +SFX 999 0 s/214,216,54321 . + +SFX 214 Y 1 +SFX 214 0 bar . + +SFX 216 Y 1 +SFX 216 0 baz . + +PFX 54321 Y 1 +PFX 54321 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic new file mode 100644 index 000000000..927c45f2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.dic @@ -0,0 +1,2 @@ +1 +foo/999,54321 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagnum.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff new file mode 100644 index 000000000..d0f75c185 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.aff @@ -0,0 +1,15 @@ +# UTF-8 flags +FLAG UTF-8 + +SFX A Y 1 +SFX A 0 s/ÖüÜ . +#SFX A 0 s/ÖüÖÜ . + +SFX Ö Y 1 +SFX Ö 0 bar . + +SFX ü Y 1 +SFX ü 0 baz . + +PFX Ü Y 1 +PFX Ü 0 un . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic new file mode 100644 index 000000000..2944490c9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.dic @@ -0,0 +1,2 @@ +1 +foo/AÜ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good new file mode 100644 index 000000000..d5c27b1a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.good @@ -0,0 +1,8 @@ +foo +foos +foosbar +foosbaz +unfoo +unfoos +unfoosbar +unfoosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/flagutf8.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff new file mode 100644 index 000000000..56cdabe5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.aff @@ -0,0 +1,12 @@ +# fogemorphemes: special morphemes in compounds +# +# Swedish example: +# gata + kontoret = gatukontoret + +COMPOUNDFLAG X +COMPOUNDBEGIN Y +ONLYINCOMPOUND Z +COMPOUNDPERMITFLAG P + +SFX A Y 1 +SFX A a u/YPZ . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic new file mode 100644 index 000000000..1b76380d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.dic @@ -0,0 +1,3 @@ +2 +gata/A +kontoret/X diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good new file mode 100644 index 000000000..01e77d561 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.good @@ -0,0 +1,3 @@ +gata +kontoret +gatukontoret diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong new file mode 100644 index 000000000..f920745c7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fogemorpheme.wrong @@ -0,0 +1,3 @@ +gatu +gatakontoret +kontoretgatu diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff new file mode 100644 index 000000000..de7f8ad9a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.aff @@ -0,0 +1,11 @@ +# FORBIDDENWORD flag +# The signed word, and its suffixed forms are all forbidden, +# excepts with root homonyms. +# Useful for forbidding bad suffixed forms or compounds. + + +FORBIDDENWORD X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic new file mode 100644 index 000000000..78f2ee3d1 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.dic @@ -0,0 +1,8 @@ +5 +foo/S [1] +foo/YX [2] +foo/Y [3] +foo/S [4] +bar/YS [5] +bars/X +foos/X diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good new file mode 100644 index 000000000..7bd112e9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.good @@ -0,0 +1,3 @@ +foo +bar + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong new file mode 100644 index 000000000..5752c1e44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forbiddenword.wrong @@ -0,0 +1,4 @@ +bars +foos +foobar +barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff new file mode 100644 index 000000000..5eebcbdab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.aff @@ -0,0 +1,4 @@ +# force capitalized compound +TRY F +FORCEUCASE A +COMPOUNDFLAG C diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic new file mode 100644 index 000000000..82fd93b30 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.dic @@ -0,0 +1,4 @@ +3 +foo/C +bar/C +baz/CA diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good new file mode 100644 index 000000000..37ecf4957 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.good @@ -0,0 +1,7 @@ +foo +bar +baz +foobar +Foobaz +foobazbar +Foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug new file mode 100644 index 000000000..6a77cbd06 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.sug @@ -0,0 +1,2 @@ +Foobaz +Foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong new file mode 100644 index 000000000..1503e42dd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/forceucase.wrong @@ -0,0 +1,2 @@ +foobaz +foobarbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff new file mode 100644 index 000000000..d60cb74d7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.aff @@ -0,0 +1,15 @@ +# FULLSTRIP option: Hunspell can strip full words by affix rules +# see OpenOffice.org Issue #80145 +# test data from Davide Prina + +FULLSTRIP + +SET ISO8859-15 +TRY aioertnsclmdpgubzfvhàq'ACMSkBGPLxEyRTVòIODNwFéùèìjUZKHWJYQX + +SFX A Y 3 # verbo andare (verb to go) +SFX A andare vado andare # io vado (I go) +SFX A andare va andare # tu vai (you go) +SFX A are iamo andare # noi andiamo (we go) + + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic new file mode 100644 index 000000000..553113d44 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.dic @@ -0,0 +1,4 @@ +2 +andare/A +riandare/A + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good new file mode 100644 index 000000000..1240e71f5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.good @@ -0,0 +1,9 @@ +andare +vado +va +andiamo +riandare +rivado +riva +riandiamo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/fullstrip.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff new file mode 100644 index 000000000..5ff25872c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.aff @@ -0,0 +1,91 @@ +# German compounding + +# handle special casing of German sharp s + +CHECKSHARPS + +# compound flags + +COMPOUNDBEGIN U +COMPOUNDMIDDLE V +COMPOUNDEND W + +# Prefixes are allowed at the beginning of compounds, +# suffixes are allowed at the end of compounds by default: +# (prefix)?(root)+(affix)? +# Affixes with COMPOUNDPERMITFLAG may be inside of compounds. +COMPOUNDPERMITFLAG P + +# for German fogemorphemes (Fuge-element) +# Hint: ONLYINCOMPOUND is not required everywhere, but the +# checking will be a little faster with it. + +ONLYINCOMPOUND X + +# forbid uppercase characters at compound word bounds +CHECKCOMPOUNDCASE + +# for handling Fuge-elements with dashes (Arbeits-) +# dash will be a special word + +COMPOUNDMIN 1 +WORDCHARS - + +# compound settings and fogemorpheme for `Arbeit' + +SFX A Y 3 +SFX A 0 s/UPX . +SFX A 0 s/VPDX . +SFX A 0 0/WXD . + +SFX B Y 2 +SFX B 0 0/UPX . +SFX B 0 0/VWXDP . + +# a suffix for `Computer' + +SFX C Y 1 +SFX C 0 n/WD . + +# for forbid exceptions (*Arbeitsnehmer) + +FORBIDDENWORD Z + +# dash prefix for compounds with dash (Arbeits-Computer) + +PFX - Y 1 +PFX - 0 -/P . + +# decapitalizing prefix +# circumfix for positioning in compounds + +PFX D Y 29 +PFX D A a/PX A +PFX D /PX +PFX D B b/PX B +PFX D C c/PX C +PFX D D d/PX D +PFX D E e/PX E +PFX D F f/PX F +PFX D G g/PX G +PFX D H h/PX H +PFX D I i/PX I +PFX D J j/PX J +PFX D K k/PX K +PFX D L l/PX L +PFX D M m/PX M +PFX D N n/PX N +PFX D O o/PX O +PFX D /PX +PFX D P p/PX P +PFX D Q q/PX Q +PFX D R r/PX R +PFX D S s/PX S +PFX D T t/PX T +PFX D U u/PX U +PFX D /PX +PFX D V v/PX V +PFX D W w/PX W +PFX D X x/PX X +PFX D Y y/PX Y +PFX D Z z/PX Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic new file mode 100644 index 000000000..5db6783a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.dic @@ -0,0 +1,5 @@ +4 +Arbeit/A- +Computer/BC- +-/W +Arbeitsnehmer/Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good new file mode 100644 index 000000000..e4945553c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.good @@ -0,0 +1,20 @@ +Computer +Computern +Arbeit +Arbeits- +Computerarbeit +Computerarbeits- +Arbeitscomputer +Computercomputer +Computercomputern +Arbeitscomputern +Computerarbeitscomputer +Computerarbeitscomputern +Arbeitscomputercomputer +Computercomputerarbeit +Arbeitscomputerarbeit +Arbeitsarbeitsarbeit +Computerarbeitsarbeit +Computerarbeits-Computer +Computerarbeits-Computern +Computer-Arbeit diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong new file mode 100644 index 000000000..c5f2ba115 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompounding.wrong @@ -0,0 +1,50 @@ +computer +computern +arbeit +Arbeits +arbeits +ComputerArbeit +ComputernArbeit +Computernarbeit +ComputerArbeits +Arbeitcomputer +Arbeitcomputern +ArbeitsComputer +ArbeitsComputern +Computerarbeitcomputer +ComputerArbeitcomputer +ComputerArbeitscomputer +Computerarbeitcomputern +ComputerArbeitcomputern +ComputerArbeitscomputern +Arbeitscomputerarbeits +Arbeitscomputernarbeits +Computerarbeits-computer +Arbeitsnehmer +computers +computern +computernarbeit +computernArbeit +computerArbeit +computerArbeits +arbeitcomputer +arbeitsComputer +computerarbeitcomputer +computerArbeitcomputer +computerArbeitscomputer +arbeitscomputerarbeits +computerarbeits-computer +arbeitsnehmer +computernarbeit +computernArbeit +arbeits- +computerarbeit +computerarbeits- +arbeitscomputer +arbeitscomputern +computerarbeitscomputer +computerarbeitscomputern +computerarbeitscomputers +arbeitscomputerarbeit +computerarbeits-Computer +computerarbeits-Computern diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff new file mode 100644 index 000000000..3e06f0647 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.aff @@ -0,0 +1,96 @@ +# German compounding + +# handle special casing of German sharp s + +CHECKSHARPS + +# compound flags + +COMPOUNDBEGIN U +COMPOUNDMIDDLE V +COMPOUNDEND W + +# Prefixes are allowed at the beginning of compounds, +# suffixes are allowed at the end of compounds by default: +# (prefix)?(root)+(affix)? +# Affixes with COMPOUNDPERMITFLAG may be inside of compounds. +COMPOUNDPERMITFLAG P + +# for German fogemorphemes (Fuge-element) +# Hint: ONLYINCOMPOUND is not required everywhere, but the +# checking will be a little faster with it. + +ONLYINCOMPOUND X + +# for decapitalizing nouns with fogemorphemes + +CIRCUMFIX Y + +# for handling Fuge-elements with dashes (Arbeits-) +# dash will be a special word + +COMPOUNDMIN 1 +WORDCHARS - + +# compound settings and fogemorpheme for `Arbeit' + +SFX A Y 3 +SFX A 0 s/UPX . +SFX A 0 s/VPXDY . +SFX A 0 0/WXDY . + +# compound settings for `Computer' + +SFX B Y 2 +SFX B 0 0/UPX . +SFX B 0 0/VWPXDY . + +# a suffix for `Computer' + +SFX C Y 2 +SFX C 0 n . +SFX C 0 n/WXDY . + +# for forbid exceptions (*Arbeitsnehmer) + +FORBIDDENWORD Z + +# dash prefix for compounds with dash (Arbeits-Computer) + +PFX - Y 2 +PFX - 0 -/PUVW . +PFX - 0 -/PY . + +# decapitalizing prefix +# circumfix for positioning in compounds + +PFX D Y 29 +PFX D A a/PXY A +PFX D /PXY +PFX D B b/PXY B +PFX D C c/PXY C +PFX D D d/PXY D +PFX D E e/PXY E +PFX D F f/PXY F +PFX D G g/PXY G +PFX D H h/PXY H +PFX D I i/PXY I +PFX D J j/PXY J +PFX D K k/PXY K +PFX D L l/PXY L +PFX D M m/PXY M +PFX D N n/PXY N +PFX D O o/PXY O +PFX D /PXY +PFX D P p/PXY P +PFX D Q q/PXY Q +PFX D R r/PXY R +PFX D S s/PXY S +PFX D T t/PXY T +PFX D U u/PXY U +PFX D /PXY +PFX D V v/PXY V +PFX D W w/PXY W +PFX D X x/PXY X +PFX D Y y/PXY Y +PFX D Z z/PXY Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic new file mode 100644 index 000000000..5db6783a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.dic @@ -0,0 +1,5 @@ +4 +Arbeit/A- +Computer/BC- +-/W +Arbeitsnehmer/Z diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good new file mode 100644 index 000000000..5357bff16 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.good @@ -0,0 +1,14 @@ +Computer +Computern +Arbeit +Arbeits- +Computerarbeit +Computerarbeits- +Arbeitscomputer +Arbeitscomputern +Computerarbeitscomputer +Computerarbeitscomputern +Arbeitscomputerarbeit +Computerarbeits-Computer +Computerarbeits-Computern +Computer-Arbeit diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong new file mode 100644 index 000000000..c5f2ba115 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/germancompoundingold.wrong @@ -0,0 +1,50 @@ +computer +computern +arbeit +Arbeits +arbeits +ComputerArbeit +ComputernArbeit +Computernarbeit +ComputerArbeits +Arbeitcomputer +Arbeitcomputern +ArbeitsComputer +ArbeitsComputern +Computerarbeitcomputer +ComputerArbeitcomputer +ComputerArbeitscomputer +Computerarbeitcomputern +ComputerArbeitcomputern +ComputerArbeitscomputern +Arbeitscomputerarbeits +Arbeitscomputernarbeits +Computerarbeits-computer +Arbeitsnehmer +computers +computern +computernarbeit +computernArbeit +computerArbeit +computerArbeits +arbeitcomputer +arbeitsComputer +computerarbeitcomputer +computerArbeitcomputer +computerArbeitscomputer +arbeitscomputerarbeits +computerarbeits-computer +arbeitsnehmer +computernarbeit +computernArbeit +arbeits- +computerarbeit +computerarbeits- +arbeitscomputer +arbeitscomputern +computerarbeitscomputer +computerarbeitscomputern +computerarbeitscomputers +arbeitscomputerarbeit +computerarbeits-Computer +computerarbeits-Computern diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff b/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff new file mode 100644 index 000000000..96755c7ec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.aff @@ -0,0 +1,203 @@ +# Ngram suggestions +# - fix case problem +# - detect character swapping (keep only these suggestions) +# - lesser suggestions +# - weight with common subsequence algorithm +# - suggest uppercased words + +# 2007-02-05: +# now not neighbour character replacements and character movings are +# detected by not ngram suggestions, too. + +# OpenOffice.org's en_US.aff file + +SET ISO8859-1 +TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' + +WORDCHARS ' + +PFX A Y 1 +PFX A 0 re . + +PFX I Y 1 +PFX I 0 in . + +PFX U Y 1 +PFX U 0 un . + +PFX C Y 1 +PFX C 0 de . + +PFX E Y 1 +PFX E 0 dis . + +PFX F Y 1 +PFX F 0 con . + +PFX K Y 1 +PFX K 0 pro . + +SFX V N 2 +SFX V e ive e +SFX V 0 ive [^e] + +SFX N Y 3 +SFX N e ion e +SFX N y ication y +SFX N 0 en [^ey] + +SFX X Y 3 +SFX X e ions e +SFX X y ications y +SFX X 0 ens [^ey] + +SFX H N 2 +SFX H y ieth y +SFX H 0 th [^y] + +SFX Y Y 1 +SFX Y 0 ly . + +SFX G Y 2 +SFX G e ing e +SFX G 0 ing [^e] + +SFX J Y 2 +SFX J e ings e +SFX J 0 ings [^e] + +SFX D Y 4 +SFX D 0 d e +SFX D y ied [^aeiou]y +SFX D 0 ed [^ey] +SFX D 0 ed [aeiou]y + +SFX T N 4 +SFX T 0 st e +SFX T y iest [^aeiou]y +SFX T 0 est [aeiou]y +SFX T 0 est [^ey] + +SFX R Y 4 +SFX R 0 r e +SFX R y ier [^aeiou]y +SFX R 0 er [aeiou]y +SFX R 0 er [^ey] + +SFX Z Y 4 +SFX Z 0 rs e +SFX Z y iers [^aeiou]y +SFX Z 0 ers [aeiou]y +SFX Z 0 ers [^ey] + +SFX S Y 4 +SFX S y ies [^aeiou]y +SFX S 0 s [aeiou]y +SFX S 0 es [sxzh] +SFX S 0 s [^sxzhy] + +SFX P Y 3 +SFX P y iness [^aeiou]y +SFX P 0 ness [aeiou]y +SFX P 0 ness [^y] + +SFX M Y 1 +SFX M 0 's . + +SFX B Y 3 +SFX B 0 able [^aeiou] +SFX B 0 able ee +SFX B e able [^aeiou]e + +SFX L Y 1 +SFX L 0 ment . + +REP 88 +REP a ei +REP ei a +REP a ey +REP ey a +REP ai ie +REP ie ai +REP are air +REP are ear +REP are eir +REP air are +REP air ere +REP ere air +REP ere ear +REP ere eir +REP ear are +REP ear air +REP ear ere +REP eir are +REP eir ere +REP ch te +REP te ch +REP ch ti +REP ti ch +REP ch tu +REP tu ch +REP ch s +REP s ch +REP ch k +REP k ch +REP f ph +REP ph f +REP gh f +REP f gh +REP i igh +REP igh i +REP i uy +REP uy i +REP i ee +REP ee i +REP j di +REP di j +REP j gg +REP gg j +REP j ge +REP ge j +REP s ti +REP ti s +REP s ci +REP ci s +REP k cc +REP cc k +REP k qu +REP qu k +REP kw qu +REP o eau +REP eau o +REP o ew +REP ew o +REP oo ew +REP ew oo +REP ew ui +REP ui ew +REP oo ui +REP ui oo +REP ew u +REP u ew +REP oo u +REP u oo +REP u oe +REP oe u +REP u ieu +REP ieu u +REP ue ew +REP ew ue +REP uff ough +REP oo ieu +REP ieu oo +REP ier ear +REP ear ier +REP ear air +REP air ear +REP w qu +REP qu w +REP z ss +REP ss z +REP shun tion +REP shun sion +REP shun cion diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic b/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic new file mode 100644 index 000000000..0c61f0031 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.dic @@ -0,0 +1,15 @@ +15 +endangerment/SM +ferment/FSCM +preferment/SM +impermanent/Y +permanent/YSP +semipermanent/Y +empowerment/MS +supermen +tournament/MS +ornamental/SY +ornament/GSDM +supernatant +pimpernel +UNESCO/M diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.good b/extensions/spellcheck/hunspell/tests/unit/data/i35725.good new file mode 100644 index 000000000..052ba8418 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.good @@ -0,0 +1 @@ +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug b/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug new file mode 100644 index 000000000..a8bf1d980 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.sug @@ -0,0 +1,10 @@ +permanent, preferment +permanent, ornament +permanent +Permanent, Preferment +Permanent, Ornament +Permanent +UNESCO +UNESCO +UNESCO's +UNESCO's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.test b/extensions/spellcheck/hunspell/tests/unit/data/i35725.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong new file mode 100644 index 000000000..573e195d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i35725.wrong @@ -0,0 +1,10 @@ +permenant +pernament +pernemant +Permenant +Pernament +Pernemant +unesco +Unesco +unesco's +Unesco's diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff b/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff new file mode 100644 index 000000000..9fac6d84c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.aff @@ -0,0 +1,2 @@ +# check numbers with separators +WORDCHARS 0123456789.-, diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic b/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic new file mode 100644 index 000000000..aec5d506b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.dic @@ -0,0 +1,2 @@ +1 +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.good b/extensions/spellcheck/hunspell/tests/unit/data/i53643.good new file mode 100644 index 000000000..116333452 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.good @@ -0,0 +1,19 @@ +1 +12 +123 +1234 +12345 +123456 +1234567 +1.1 +1.12 +1.123 +1.1234 +1.12345 +1.123456 +12.1 +123.12 +1234.123 +12345.1234 +123456.12345 +1234567.123456 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.test b/extensions/spellcheck/hunspell/tests/unit/data/i53643.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong new file mode 100644 index 000000000..45c61d298 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i53643.wrong @@ -0,0 +1,4 @@ +1..2 +1,,2 +1.,2 +1,.2 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff b/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff new file mode 100644 index 000000000..46281e1c5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.aff @@ -0,0 +1,2 @@ +# Missing capitalized suggestion for capitalized bad words +SET ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic b/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic new file mode 100644 index 000000000..e26d6f9c8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.dic @@ -0,0 +1,2 @@ +1 +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.good b/extensions/spellcheck/hunspell/tests/unit/data/i54633.good new file mode 100644 index 000000000..a115f67ed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.good @@ -0,0 +1,2 @@ +diter +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug b/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug new file mode 100644 index 000000000..a115f67ed --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.sug @@ -0,0 +1,2 @@ +diter +diter diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.test b/extensions/spellcheck/hunspell/tests/unit/data/i54633.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong new file mode 100644 index 000000000..579a45dab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54633.wrong @@ -0,0 +1,2 @@ +editer +Editer diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff b/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff new file mode 100644 index 000000000..37cc5c53d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.aff @@ -0,0 +1,2 @@ +# ISO-8859-15 (extended latin-1) support for French, Finnish and EURO symbol +SET ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic b/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic new file mode 100644 index 000000000..414f9b8d3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.dic @@ -0,0 +1,3 @@ +2 +cur +uvre diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.good b/extensions/spellcheck/hunspell/tests/unit/data/i54980.good new file mode 100644 index 000000000..fc41c90aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.good @@ -0,0 +1,4 @@ +cur +uvre +CUR +UVRE diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i54980.test b/extensions/spellcheck/hunspell/tests/unit/data/i54980.test new file mode 100644 index 000000000..09619572e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i54980.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-15 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff b/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff new file mode 100644 index 000000000..11249d4f2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.aff @@ -0,0 +1,4 @@ +# case suggestions +MAXNGRAMSUGS 0 +# capitalise baz->Baz +TRY B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic b/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic new file mode 100644 index 000000000..19e1980ba --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.dic @@ -0,0 +1,5 @@ +4 +foo +bar +Baz +Boo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.good b/extensions/spellcheck/hunspell/tests/unit/data/i58202.good new file mode 100644 index 000000000..88a079a55 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.good @@ -0,0 +1,10 @@ +foo +bar +Foo +Bar +Baz +Boo +FOO +BAR +BAZ +BOO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug b/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug new file mode 100644 index 000000000..bc784acef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.sug @@ -0,0 +1,13 @@ +foo, Boo +Bar +Baz +Boo +foo bar +foo Bar +Foo bar +Foo Bar +foo Baz +Foo Baz +Baz foo +Baz Foo +Baz Boo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.test b/extensions/spellcheck/hunspell/tests/unit/data/i58202.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong new file mode 100644 index 000000000..886584d80 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i58202.wrong @@ -0,0 +1,13 @@ +fOO +BAr +baz +BOo +foobar +fooBar +Foobar +FooBar +fooBaz +FooBaz +Bazfoo +BazFoo +BazBoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff b/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff new file mode 100644 index 000000000..f0c639e8d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.aff @@ -0,0 +1,7 @@ +# Sant'Elia -> SANT'ELIA (Italian) +# OpenOffice.org Issue 68658 + +PFX a Y 1 +PFX a 0 Sant' E + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic b/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic new file mode 100644 index 000000000..966010835 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.dic @@ -0,0 +1,2 @@ +1 +Elia/a diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.test b/extensions/spellcheck/hunspell/tests/unit/data/i68568.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong new file mode 100644 index 000000000..998e9f4e4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568.wrong @@ -0,0 +1,5 @@ +sant'elia +sant'Elia +Sant'elia +Sant' +SANT' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff new file mode 100644 index 000000000..7076ee938 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.aff @@ -0,0 +1,8 @@ +# Sant'Elia -> SANT'ELIA (Italian) +# OpenOffice.org Issue 68658 +SET UTF-8 + +PFX a Y 1 +PFX a 0 Foó' B + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic new file mode 100644 index 000000000..bc38229fa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.dic @@ -0,0 +1,2 @@ +1 +Bár/a diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong new file mode 100644 index 000000000..0713c1369 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/i68568utf.wrong @@ -0,0 +1,5 @@ +foó'bár +foó'Bár +Foó'bár +foó' +FOÓ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff b/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff new file mode 100644 index 000000000..36cf7a223 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.aff @@ -0,0 +1,10 @@ +# input conversion (accept comma acuted letters also with cedilla, +# as de facto replacement of the Romanian standard) +SET UTF-8 + +ICONV 4 +ICONV ş ș +ICONV ţ ț +ICONV Ş Ș +ICONV Ţ Ț + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic b/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic new file mode 100644 index 000000000..8326eee2d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.dic @@ -0,0 +1,5 @@ +4 +Chișinău +Țepes +ț +Ș diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.good b/extensions/spellcheck/hunspell/tests/unit/data/iconv.good new file mode 100644 index 000000000..746cf1e53 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.good @@ -0,0 +1,6 @@ +Chișinău +Chişinău +Țepes +Ţepes +Ş +ţ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/iconv.test b/extensions/spellcheck/hunspell/tests/unit/data/iconv.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/iconv.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff b/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff new file mode 100644 index 000000000..238dc15e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.aff @@ -0,0 +1,5 @@ +# ignore characters in words (for Arabic Harakat or Hebrew niqqud) +IGNORE aeiou + +PFX A Y 1 +PFX A 0 re . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic b/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic new file mode 100644 index 000000000..846983b7d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.dic @@ -0,0 +1,3 @@ +2 +xmpl +expression/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.good b/extensions/spellcheck/hunspell/tests/unit/data/ignore.good new file mode 100644 index 000000000..d7dd645c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.good @@ -0,0 +1,6 @@ +example +expression +xmpl +xprssn +reexpression +rxprssn diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignore.test b/extensions/spellcheck/hunspell/tests/unit/data/ignore.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignore.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff new file mode 100644 index 000000000..8646676d0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.aff @@ -0,0 +1,6 @@ +# Arabic test for feature ignoring diacritics +SET UTF-8 +# Arabic diacritics (harakat): +# sukun, shadda, kasra, damma, fatha, kasratan, dammantan, fathatan (left to right) +IGNORE ًٌٍَُِّْ +WORDCHARS ًٌٍَُِّْ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic new file mode 100644 index 000000000..d4a2a81e7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.dic @@ -0,0 +1,10 @@ +9 +طِير +فَتحة +ضُمة +كِسرة +فتحًتان +ضمتانٌ +كسرتاٍن +شدّة +سكوْن diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good new file mode 100644 index 000000000..d463cd59f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.good @@ -0,0 +1,9 @@ +طير +فتحة +ضمة +كسرة +فتحتان +ضمتان +كسرتان +شدة +سكون diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ignoreutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff new file mode 100644 index 000000000..b08006bf7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.aff @@ -0,0 +1,3 @@ +# keep case in signed words +KEEPCASE A +WORDCHARS . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic new file mode 100644 index 000000000..bf9992acf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.dic @@ -0,0 +1,5 @@ +4 +foo/A +Bar/A +baz./A +Quux./A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good new file mode 100644 index 000000000..e6ff1817d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.good @@ -0,0 +1,4 @@ +foo +Bar +baz. +Quux. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug new file mode 100644 index 000000000..551dd8bb3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.sug @@ -0,0 +1,8 @@ +foo +foo +Bar +Bar +baz. +baz. +Quux. +Quux. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong new file mode 100644 index 000000000..3b7914291 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/keepcase.wrong @@ -0,0 +1,8 @@ +Foo +FOO +BAR +bar +Baz. +BAZ. +quux. +QUUX. diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.aff b/extensions/spellcheck/hunspell/tests/unit/data/korean.aff new file mode 100644 index 000000000..979e3c228 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.aff @@ -0,0 +1 @@ +SET UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.dic b/extensions/spellcheck/hunspell/tests/unit/data/korean.dic new file mode 100644 index 000000000..95cb4508e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.dic @@ -0,0 +1,3 @@ +2 +들어오세요 +안녕하세요 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.good b/extensions/spellcheck/hunspell/tests/unit/data/korean.good new file mode 100644 index 000000000..660d506bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.good @@ -0,0 +1,2 @@ +들어오세요 +안녕하세요 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.test b/extensions/spellcheck/hunspell/tests/unit/data/korean.test new file mode 100644 index 000000000..4d59c4212 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong b/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong new file mode 100644 index 000000000..5ea85cead --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/korean.wrong @@ -0,0 +1 @@ +들어오세 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.aff b/extensions/spellcheck/hunspell/tests/unit/data/map.aff new file mode 100644 index 000000000..3e78baba6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.aff @@ -0,0 +1,9 @@ +# With MAP suggestion, Hunspell can add missing accents to a word. + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +MAP 3 +MAP u +MAP o +MAP (ss) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.dic b/extensions/spellcheck/hunspell/tests/unit/data/map.dic new file mode 100644 index 000000000..744394f0c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.dic @@ -0,0 +1,4 @@ +3 +Frhstck +tkrfr +gro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.sug b/extensions/spellcheck/hunspell/tests/unit/data/map.sug new file mode 100644 index 000000000..cadb75422 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.sug @@ -0,0 +1,3 @@ +Frhstck +tkrfr +gro diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.test b/extensions/spellcheck/hunspell/tests/unit/data/map.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/map.wrong b/extensions/spellcheck/hunspell/tests/unit/data/map.wrong new file mode 100644 index 000000000..251c8a1e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/map.wrong @@ -0,0 +1,3 @@ +Fruhstuck +tukorfuro +gross diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff b/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff new file mode 100644 index 000000000..30edb2a78 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.aff @@ -0,0 +1,11 @@ +# With MAP suggestion, Hunspell can add missing accents to a word. + +SET UTF-8 + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +MAP 3 +MAP uúü +MAP öóo +MAP ß(ss) diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic b/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic new file mode 100644 index 000000000..1c6fa8d05 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.dic @@ -0,0 +1,4 @@ +3 +Frühstück +tükörfúró +groß diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug b/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug new file mode 100644 index 000000000..81d09e021 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.sug @@ -0,0 +1,3 @@ +Frühstück +tükörfúró +groß diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.test b/extensions/spellcheck/hunspell/tests/unit/data/maputf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong new file mode 100644 index 000000000..251c8a1e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/maputf.wrong @@ -0,0 +1,3 @@ +Fruhstuck +tukorfuro +gross diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.aff b/extensions/spellcheck/hunspell/tests/unit/data/morph.aff new file mode 100644 index 000000000..608085860 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.aff @@ -0,0 +1,12 @@ +# example for morphological analysis, stemming and generation +PFX P Y 1 +PFX P 0 un . dp:pfx_un sp:un + +SFX S Y 1 +SFX S 0 s . is:plur + +SFX Q Y 1 +SFX Q 0 s . is:sg_3 + +SFX R Y 1 +SFX R 0 able/PS . ds:der_able diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.dic b/extensions/spellcheck/hunspell/tests/unit/data/morph.dic new file mode 100644 index 000000000..f8d58a6d4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.dic @@ -0,0 +1,10 @@ +9 +drink/S po:noun +drink/RQ po:verb al:drank al:drunk ts:present +drank po:verb st:drink is:past_1 +drunk po:verb st:drink is:past_2 +eat/RQ po:verb al:ate al:eaten ts:present +ate po:verb st:eat is:past_1 +eaten po:verb st:eat is:past_2 +phenomenon po:noun al:phenomena +phenomena po:noun st:phenomenon is:plur diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.good b/extensions/spellcheck/hunspell/tests/unit/data/morph.good new file mode 100644 index 000000000..9f0d24768 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.good @@ -0,0 +1,26 @@ +drink +drinks +drinkable +drinkables +undrinkable +undrinkables +drank +drunk +phenomenon +phenomena +drink eat +drink eats +drink ate +drink eaten +drink eatable +drink eatables +drink phenomena +drinks eat +drinks eats +drinks ate +drinks eaten +drinks eatable +drinks eatables +drinks phenomena +undrinkable phenomena +phenomenon drinks diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.morph b/extensions/spellcheck/hunspell/tests/unit/data/morph.morph new file mode 100644 index 000000000..9965d7ea8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.morph @@ -0,0 +1,48 @@ +> drink +analyze(drink) = st:drink po:noun +analyze(drink) = st:drink po:verb al:drank al:drunk ts:present +stem(drink) = drink +> drinks +analyze(drinks) = st:drink po:verb al:drank al:drunk ts:present is:sg_3 +analyze(drinks) = st:drink po:noun is:plur +stem(drinks) = drink +> drinkable +analyze(drinkable) = st:drink po:verb al:drank al:drunk ts:present ds:der_able +stem(drinkable) = drinkable +> drinkables +analyze(drinkables) = st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur +stem(drinkables) = drinkable +> undrinkable +analyze(undrinkable) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able +stem(undrinkable) = undrinkable +> undrinkables +analyze(undrinkables) = dp:pfx_un sp:un st:drink po:verb al:drank al:drunk ts:present ds:der_able is:plur +stem(undrinkables) = undrinkable +> drank +analyze(drank) = po:verb st:drink is:past_1 +stem(drank) = drink +> drunk +analyze(drunk) = po:verb st:drink is:past_2 +stem(drunk) = drink +> phenomenon +analyze(phenomenon) = st:phenomenon po:noun al:phenomena +stem(phenomenon) = phenomenon +> phenomena +analyze(phenomena) = po:noun st:phenomenon is:plur +stem(phenomena) = phenomenon +generate(drink, eat) = drink +generate(drink, eats) = drinks +generate(drink, ate) = drank +generate(drink, eaten) = drunk +generate(drink, eatable) = drinkable +generate(drink, eatables) = drinkables +generate(drink, phenomena) = drinks +generate(drinks, eat) = drink +generate(drinks, eats) = drinks +generate(drinks, ate) = drank +generate(drinks, eaten) = drunk +generate(drinks, eatable) = drinkable +generate(drinks, eatables) = drinkables +generate(drinks, phenomena) = drinks +generate(undrinkable, phenomena) = undrinkables +generate(phenomenon, drinks) = phenomena diff --git a/extensions/spellcheck/hunspell/tests/unit/data/morph.test b/extensions/spellcheck/hunspell/tests/unit/data/morph.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/morph.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff new file mode 100644 index 000000000..a5981ef69 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.aff @@ -0,0 +1,5 @@ +NEEDAFFIX X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 s/Y . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic new file mode 100644 index 000000000..b5792765e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.dic @@ -0,0 +1,3 @@ +2 +foo/YXA +bar/Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good new file mode 100644 index 000000000..f9e0663f3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.good @@ -0,0 +1,3 @@ +bar +foos +barfoos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix.wrong @@ -0,0 +1 @@ +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff new file mode 100644 index 000000000..c434dac66 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.aff @@ -0,0 +1,2 @@ +NEEDAFFIX X +COMPOUNDFLAG Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic new file mode 100644 index 000000000..ff32e878b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.dic @@ -0,0 +1,5 @@ +4 +foo st:foo id:1 +foo/YX st:foo id:2 +foo/Y st:foo id:3 +bar/Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good new file mode 100644 index 000000000..7e4b098ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.good @@ -0,0 +1,5 @@ +foo +bar +foobar +barfoo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph new file mode 100644 index 000000000..0f3e47431 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.morph @@ -0,0 +1,13 @@ +> foo +analyze(foo) = st:foo id:1 +analyze(foo) = st:foo id:3 +stem(foo) = foo +> bar +analyze(bar) = st:bar +stem(bar) = bar +> foobar +analyze(foobar) = pa:foo st:foo id:3 pa:bar +stem(foobar) = foo +> barfoo +analyze(barfoo) = pa:bar st:bar pa:foo st:foo id:3 +stem(barfoo) = barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff new file mode 100644 index 000000000..5d55d38e9 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.aff @@ -0,0 +1,8 @@ +# neeadaffix on affixes +NEEDAFFIX X + +SFX A Y 1 +SFX A 0 s/XB . + +SFX B Y 1 +SFX B 0 baz . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic new file mode 100644 index 000000000..001d95e77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.dic @@ -0,0 +1,2 @@ +2 +foo/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good new file mode 100644 index 000000000..dc9a6a97d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.good @@ -0,0 +1,2 @@ +foo +foosbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong new file mode 100644 index 000000000..c09c408f2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix3.wrong @@ -0,0 +1 @@ +foos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff new file mode 100644 index 000000000..c434dac66 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.aff @@ -0,0 +1,2 @@ +NEEDAFFIX X +COMPOUNDFLAG Y diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic new file mode 100644 index 000000000..96f80c12b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.dic @@ -0,0 +1,5 @@ +4 +foo/X [1] +foo/Y [2] +foo/YX [3] +bar/Y [4] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good new file mode 100644 index 000000000..7e4b098ef --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.good @@ -0,0 +1,5 @@ +foo +bar +foobar +barfoo + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix4.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff new file mode 100644 index 000000000..6399a3e98 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.aff @@ -0,0 +1,13 @@ +# on affixes +NEEDAFFIX X + +SFX A Y 2 +SFX A 0 suf/B . +SFX A 0 pseudosuf/XB . + +SFX B Y 1 +SFX B 0 bar . + +PFX C Y 2 +PFX C 0 pre . +PFX C 0 pseudopre/X . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic new file mode 100644 index 000000000..83131e27a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.dic @@ -0,0 +1,2 @@ +1 +foo/AC diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good new file mode 100644 index 000000000..d1b86bf83 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.good @@ -0,0 +1,11 @@ +foo +prefoo +foosuf +prefoosuf +foosufbar +prefoosufbar +pseudoprefoosuf +pseudoprefoosufbar +pseudoprefoopseudosufbar +prefoopseudosuf +prefoopseudosufbar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong new file mode 100644 index 000000000..fdd1797fd --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/needaffix5.wrong @@ -0,0 +1,3 @@ +pseudoprefoo +foopseudosuf +pseudoprefoopseudosuf diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff new file mode 100644 index 000000000..19e698121 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.aff @@ -0,0 +1,21 @@ +# Test fix of suffixed ngram suggestions with UTF-8 encoding and long flags. +# Based on Vitaly Piryatinsky's bug report and example. +SET UTF-8 +FLAG num + +PFX 101 Y 1 +PFX 101 0 пред . + +SFX 1381 Y 1 +SFX 1381 0 о . + +SFX 2000 Y 3 +SFX 2000 0 ам . +SFX 2000 0 ами . +SFX 2000 0 ах . + +SFX 2022 Y 4 +SFX 2022 0 а . +SFX 2022 0 у . +SFX 2022 0 ом . +SFX 2022 0 е . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic new file mode 100644 index 000000000..27ce413ae --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.dic @@ -0,0 +1,2 @@ +1 +человек/2022,2000,101 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good new file mode 100644 index 000000000..366d92a9b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.good @@ -0,0 +1 @@ +человек diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug new file mode 100644 index 000000000..58ab09b53 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.sug @@ -0,0 +1,2 @@ +человек +человек diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong new file mode 100644 index 000000000..97de996e0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/ngram-utf-fix.wrong @@ -0,0 +1,2 @@ +времячко +человеко diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff new file mode 100644 index 000000000..c9361da4c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.aff @@ -0,0 +1,5 @@ +# don't suggest word with NOSUGGEST flag (for example vulgar or obscene words) +# See OpenOffice.org Issue #55498 +# (nosuggest.sug is an empty file) +NOSUGGEST A +COMPOUNDFLAG B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic new file mode 100644 index 000000000..dc80c916d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.dic @@ -0,0 +1,3 @@ +1 +foo/AB +bar/B diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good new file mode 100644 index 000000000..ad91a5e31 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.good @@ -0,0 +1,3 @@ +foo +foobar +barfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.sug diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong new file mode 100644 index 000000000..89c7a1a9c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/nosuggest.wrong @@ -0,0 +1,3 @@ +foox +foobarx +barfoox diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff b/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff new file mode 100644 index 000000000..13a3d9b20 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.aff @@ -0,0 +1,12 @@ +# output conversion +SET UTF-8 + +OCONV 7 +OCONV a A +OCONV á Á +OCONV b B +OCONV c C +OCONV d D +OCONV e E +OCONV é É + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic b/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic new file mode 100644 index 000000000..359186cac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.dic @@ -0,0 +1,4 @@ +3 +bébé +dádá +aábcdeé diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.good b/extensions/spellcheck/hunspell/tests/unit/data/oconv.good new file mode 100644 index 000000000..6cdaab16e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.good @@ -0,0 +1,2 @@ +bébé +dádá diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug b/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug new file mode 100644 index 000000000..a191c629d --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.sug @@ -0,0 +1,3 @@ +BÉBÉ +DÁDÁ +AÁBCDEÉ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.test b/extensions/spellcheck/hunspell/tests/unit/data/oconv.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong b/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong new file mode 100644 index 000000000..73dcc895a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/oconv.wrong @@ -0,0 +1,3 @@ +béb +dád +aábcde diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff new file mode 100644 index 000000000..e700b0e54 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.aff @@ -0,0 +1,5 @@ +# words only in compounds (see also fogemorpheme example) +ONLYINCOMPOUND O +COMPOUNDFLAG A +SFX B Y 1 +SFX B 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic new file mode 100644 index 000000000..dc742f7ab --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.dic @@ -0,0 +1,3 @@ +2 +foo/A +pseudo/OAB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good new file mode 100644 index 000000000..151d59734 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.good @@ -0,0 +1,4 @@ +foo +pseudofoo +foopseudo +foopseudos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.sug diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong new file mode 100644 index 000000000..115d0c617 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound.wrong @@ -0,0 +1,2 @@ +pseudo +pseudos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff new file mode 100644 index 000000000..5d0ac5e69 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.aff @@ -0,0 +1,12 @@ +# affixes only in compounds (see also fogemorpheme example) +ONLYINCOMPOUND O +COMPOUNDFLAG A +COMPOUNDPERMITFLAG P + +SFX B Y 1 +SFX B 0 s/OP . + +# obligate fogemorpheme by forbidding the stem (0) in compounds + +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN 0/B /A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic new file mode 100644 index 000000000..1adab653b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.dic @@ -0,0 +1,3 @@ +2 +foo/A +pseudo/AB diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good new file mode 100644 index 000000000..a31ce34ac --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.good @@ -0,0 +1,3 @@ +foo +foopseudo +pseudosfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong new file mode 100644 index 000000000..29a71a3c3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/onlyincompound2.wrong @@ -0,0 +1,3 @@ +pseudos +foopseudos +pseudofoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff new file mode 100644 index 000000000..413aca404 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.aff @@ -0,0 +1,13 @@ +FLAG long +COMPOUNDBEGIN Ca +COMPOUNDMIDDLE Cb +COMPOUNDEND Cc +COMPOUNDPERMITFLAG Cp +ONLYINCOMPOUND Cx + +CHECKCOMPOUNDPATTERN 1 +CHECKCOMPOUNDPATTERN /Ch /Xs + +SFX Ch Y 2 +SFX Ch 0 s/CaCbCxCp . +SFX Ch 0 s-/CaCbCcCp . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic new file mode 100644 index 000000000..e7831b704 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.dic @@ -0,0 +1,4 @@ +3 +schoonheid/Ch +port/CcXs +sport/Cc diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good new file mode 100644 index 000000000..fbaf830be --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.good @@ -0,0 +1 @@ +schoonheidssport diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong new file mode 100644 index 000000000..3f9e8949b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat.wrong @@ -0,0 +1 @@ +schoonheidsport diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff new file mode 100644 index 000000000..22dfe69d8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.aff @@ -0,0 +1,27 @@ +# Test file based on OpenTaal's Dutch dictionary, coded by Ruud Baars + +WORDCHARS - +NOSPLITSUGS +FLAG long + +COMPOUNDBEGIN Ca +COMPOUNDMIDDLE Cb +COMPOUNDEND Cc +COMPOUNDPERMITFLAG Cp +ONLYINCOMPOUND Cx + +CHECKCOMPOUNDPATTERN 2 +CHECKCOMPOUNDPATTERN 0/Ch /Xs +CHECKCOMPOUNDPATTERN 0/Xm /Xm + +SFX CA Y 2 +SFX CA 0 /CaCp . +SFX CA 0 -/CaCp . + +SFX CB Y 2 +SFX CB 0 /CbCp . +SFX CB 0 -/CbCp . + +SFX Ch Y 2 +SFX Ch 0 s/CaCbCxCp . +SFX Ch 0 s-/CaCbCcCp . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic new file mode 100644 index 000000000..52581e942 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.dic @@ -0,0 +1,4 @@ +100 +test/CACBCc +zout/CACBXm +suiker/CACBXm
\ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good new file mode 100644 index 000000000..e604d6e2f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.good @@ -0,0 +1 @@ +zout-suikertest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong new file mode 100644 index 000000000..d8ddb16a5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-cpdpat2.wrong @@ -0,0 +1 @@ +zoutsuikertest diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff new file mode 100644 index 000000000..fa073432f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.aff @@ -0,0 +1,9 @@ +TRY r + +FORBIDDENWORD F +COMPOUNDRULE 2 +COMPOUNDRULE WW +COMPOUNDRULE WWW + +SFX S Y 1 +SFX S 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic new file mode 100644 index 000000000..44375948f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.dic @@ -0,0 +1,5 @@ +4 +foo/W +word/W +bar/WS +foowordbar/FS diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good new file mode 100644 index 000000000..73a96a784 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.good @@ -0,0 +1,3 @@ +fooword +wordbar +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug new file mode 100644 index 000000000..60111a417 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.sug @@ -0,0 +1 @@ +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong new file mode 100644 index 000000000..59dfddfb2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword1.wrong @@ -0,0 +1,5 @@ +foowordbar +foowordbars +foowordba +foowordbas +barwodfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff new file mode 100644 index 000000000..441354d6b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.aff @@ -0,0 +1,7 @@ +TRY r + +FORBIDDENWORD F +COMPOUNDFLAG W + +SFX S Y 1 +SFX S 0 s . diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic new file mode 100644 index 000000000..895dd6230 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.dic @@ -0,0 +1,5 @@ +3 +foo/WS +word/W +bar/WS +foowordbar/FS
\ No newline at end of file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good new file mode 100644 index 000000000..17cf47de3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.good @@ -0,0 +1,4 @@ +fooword +wordbar +barwordfoo +barwordfoos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug new file mode 100644 index 000000000..60111a417 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.sug @@ -0,0 +1 @@ +barwordfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong new file mode 100644 index 000000000..59dfddfb2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-forbiddenword2.wrong @@ -0,0 +1,5 @@ +foowordbar +foowordbars +foowordba +foowordbas +barwodfoo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff new file mode 100644 index 000000000..15c914bec --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.aff @@ -0,0 +1,8 @@ +KEEPCASE K +COMPOUNDBEGIN B +COMPOUNDEND E +COMPOUNDFLAG C +COMPOUNDMIN 1 +WORDCHARS - +BREAK 1 +BREAK # diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic new file mode 100644 index 000000000..b05ec131a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.dic @@ -0,0 +1,7 @@ +5 +tv-/KB +-tv/KE +word/C +NATO-/B +-NATO/E + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good new file mode 100644 index 000000000..e1c112910 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.good @@ -0,0 +1,4 @@ +tv-word +word-tv +NATO-word +word-NATO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug new file mode 100644 index 000000000..07dde3fe6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.sug @@ -0,0 +1,8 @@ +Tv-word, Tv- word, Word +Tv- word, Word +word -tv, word-tv, word +word -tv, word-tv, word +wordword-tv, word +Tv-word-tv +NATO- +-NATO diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong new file mode 100644 index 000000000..b15752ed2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/opentaal-keepcase.wrong @@ -0,0 +1,8 @@ +TV-word +Tv-word +word-TV +word-Tv +wordword-TV +TV-word-TV +Nato-word +word-nato diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.aff b/extensions/spellcheck/hunspell/tests/unit/data/phone.aff new file mode 100644 index 000000000..5a27c14d7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.aff @@ -0,0 +1,255 @@ +# phonetic suggestions by PHONE and optional ph field of dictionary words +# Documentationo of PHONE: http://aspell.net/man-html/Phonetic-Code.html + +# phonetic_english.h - phonetic transformation rules for use with phonetic.c +# Copyright (C) 2000 Björn Jacke +# +# This rule set is based on Lawrence Phillips original metaphone +# algorithm with modifications made by Michael Kuhn in his +# C implantation, more modifications by Björn Jacke when +# converting the algorithm to a rule set and minor +# touch ups by Kevin Atkinson +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1 as published by the Free Software Foundation; +# +# 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 02111-1307 USA +# +# Björn Jacke may be reached by email at bjoern.jacke@gmx.de +# +# Changelog: +# +# 2000-01-05 Björn Jacke <bjoern.jacke@gmx.de> +# - first version with translation rules derived from +# metaphone.cc distributed with aspell 0.28.3 +# - "TH" is now representated as "@" because "0" is a +# meta character +# - removed TH(!vowel) --> T; always use TH --> # instead +# - dropped "^AE" -> "E" (redundant) +# - "ing" is transformed to "N", not "NK" +# - "SCH(EO)" transforms to "SK" now +# - added R --> SILENT if (after a vowel) and no (vowel or +# "y" follows) like in "Marcy" or "abort" +# - H is SILENT in RH at beginning of words +# - H is SILENT if vowel leads and "Y" follows +# - some ".OUGH.." --> ...F exceptions added +# - "^V" transforms to "W" +# 2000-01-07 Kevin Atkinson <kevinatk@home.com> +# Converted from header to data file. +# +# 2007-08-23 László Németh <nemeth AT OOo> +# Add PHONE header and PHONE keywords +# +# version 1.1 + +PHONE 105 +PHONE AH(AEIOUY)-^ *H +PHONE AR(AEIOUY)-^ *R +PHONE A(HR)^ * +PHONE A^ * +PHONE AH(AEIOUY)- H +PHONE AR(AEIOUY)- R +PHONE A(HR) _ +PHONE BB- _ +PHONE B B +PHONE CQ- _ +PHONE CIA X +PHONE CH X +PHONE C(EIY)- S +PHONE CK K +PHONE COUGH^ KF +PHONE CC< C +PHONE C K +PHONE DG(EIY) K +PHONE DD- _ +PHONE D T +PHONE < E +PHONE EH(AEIOUY)-^ *H +PHONE ER(AEIOUY)-^ *R +PHONE E(HR)^ * +PHONE ENOUGH^$ *NF +PHONE E^ * +PHONE EH(AEIOUY)- H +PHONE ER(AEIOUY)- R +PHONE E(HR) _ +PHONE FF- _ +PHONE F F +PHONE GN^ N +PHONE GN$ N +PHONE GNS$ NS +PHONE GNED$ N +PHONE GH(AEIOUY)- K +PHONE GH _ +PHONE GG9 K +PHONE G K +PHONE H H +PHONE IH(AEIOUY)-^ *H +PHONE IR(AEIOUY)-^ *R +PHONE I(HR)^ * +PHONE I^ * +PHONE ING6 N +PHONE IH(AEIOUY)- H +PHONE IR(AEIOUY)- R +PHONE I(HR) _ +PHONE J K +PHONE KN^ N +PHONE KK- _ +PHONE K K +PHONE LAUGH^ LF +PHONE LL- _ +PHONE L L +PHONE MB$ M +PHONE MM M +PHONE M M +PHONE NN- _ +PHONE N N +PHONE OH(AEIOUY)-^ *H +PHONE OR(AEIOUY)-^ *R +PHONE O(HR)^ * +PHONE O^ * +PHONE OH(AEIOUY)- H +PHONE OR(AEIOUY)- R +PHONE O(HR) _ +PHONE PH F +PHONE PN^ N +PHONE PP- _ +PHONE P P +PHONE Q K +PHONE RH^ R +PHONE ROUGH^ RF +PHONE RR- _ +PHONE R R +PHONE SCH(EOU)- SK +PHONE SC(IEY)- S +PHONE SH X +PHONE SI(AO)- X +PHONE SS- _ +PHONE S S +PHONE TI(AO)- X +PHONE TH @ +PHONE TCH-- _ +PHONE TOUGH^ TF +PHONE TT- _ +PHONE T T +PHONE UH(AEIOUY)-^ *H +PHONE UR(AEIOUY)-^ *R +PHONE U(HR)^ * +PHONE U^ * +PHONE UH(AEIOUY)- H +PHONE UR(AEIOUY)- R +PHONE U(HR) _ +PHONE V^ W +PHONE V F +PHONE WR^ R +PHONE WH^ W +PHONE W(AEIOU)- W +PHONE X^ S +PHONE X KS +PHONE Y(AEIOU)- Y +PHONE ZZ- _ +PHONE Z S + +#The rules in a different view: +# +# Exceptions: +# +# Beginning of word: "gn", "kn-", "pn-", "wr-" ----> drop first letter +# "Aebersold", "Gnagy", "Knuth", "Pniewski", "Wright" +# +# Beginning of word: "x" ----> change to "s" +# as in "Deng Xiaopeng" +# +# Beginning of word: "wh-" ----> change to "w" +# as in "Whalen" +# Beginning of word: leading vowels are transformed to "*" +# +# "[crt]ough" and "enough" are handled separately because of "F" sound +# +# +# A --> A at beginning +# _ otherwise +# +# B --> B unless at the end of word after "m", as in "dumb", "McComb" +# +# C --> X (sh) if "-cia-" or "-ch-" +# S if "-ci-", "-ce-", or "-cy-" +# SILENT if "-sci-", "-sce-", or "-scy-", or "-cq-" +# K otherwise, including in "-sch-" +# +# D --> K if in "-dge-", "-dgy-", or "-dgi-" +# T otherwise +# +# E --> A at beginnig +# _ SILENT otherwise +# +# F --> F +# +# G --> SILENT if in "-gh-" and not at end or before a vowel +# in "-gn" or "-gned" or "-gns" +# in "-dge-" etc., as in above rule +# K if before "i", or "e", or "y" if not double "gg" +# +# K otherwise (incl. "GG"!) +# +# H --> SILENT if after vowel and no vowel or "Y" follows +# or after "-ch-", "-sh-", "-ph-", "-th-", "-gh-" +# or after "rh-" at beginning +# H otherwise +# +# I --> A at beginning +# _ SILENT otherwise +# +# J --> K +# +# K --> SILENT if after "c" +# K otherwise +# +# L --> L +# +# M --> M +# +# N --> N +# +# O --> A at beginning +# _ SILENT otherwise +# +# P --> F if before "h" +# P otherwise +# +# Q --> K +# +# R --> SILENT if after vowel and no vowel or "Y" follows +# R otherwise +# +# S --> X (sh) if before "h" or in "-sio-" or "-sia-" +# SK if followed by "ch(eo)" (SCH(EO)) +# S otherwise +# +# T --> X (sh) if "-tia-" or "-tio-" +# 0 (th) if before "h" +# silent if in "-tch-" +# T otherwise +# +# U --> A at beginning +# _ SILENT otherwise +# +# V --> V if first letter of word +# F otherwise +# +# W --> SILENT if not followed by a vowel +# W if followed by a vowel +# +# X --> KS +# +# Y --> SILENT if not followed by a vowel +# Y if followed by a vowel +# +# Z --> S diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.dic b/extensions/spellcheck/hunspell/tests/unit/data/phone.dic new file mode 100644 index 000000000..51b0743d0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.dic @@ -0,0 +1,11 @@ +10 +Brasilia +brassily +Brazilian +brilliance +brilliancy +brilliant +brain +brass +Churchillian +xxxxxxxxxx ph:Brasilia diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.sug b/extensions/spellcheck/hunspell/tests/unit/data/phone.sug new file mode 100644 index 000000000..cc22e3798 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.sug @@ -0,0 +1 @@ +Brasilia, Xxxxxxxxxx, Brilliant, Brazilian, Brassily, Brilliance diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.test b/extensions/spellcheck/hunspell/tests/unit/data/phone.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong b/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong new file mode 100644 index 000000000..ca9db395e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/phone.wrong @@ -0,0 +1 @@ +Brasillian diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.aff b/extensions/spellcheck/hunspell/tests/unit/data/rep.aff new file mode 100644 index 000000000..485755c89 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.aff @@ -0,0 +1,21 @@ +# With REP suggestions, we can fix typical language specific misspellings. + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +REP 8 +REP f ph +REP ph f +REP shun$ tion +REP ^alot$ a_lot # add the highest priority for "a lot" suggestion to "alot" +REP ^foo$ bar +REP ' _ # "un'alunno" -> "un alunno" +REP ^vinten$ vinte_e_un +REP s 's + + +SFX A Y 1 +SFX A 0 's . + + +WORDCHARS ' diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.dic b/extensions/spellcheck/hunspell/tests/unit/data/rep.dic new file mode 100644 index 000000000..f9a4c008b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.dic @@ -0,0 +1,15 @@ +10 +form +phantom +vacation +vacations +a +lot +un +alunno +bar +barbars +vinte +e +un +auto/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.sug b/extensions/spellcheck/hunspell/tests/unit/data/rep.sug new file mode 100644 index 000000000..b48a5b80e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.sug @@ -0,0 +1,8 @@ +form +phantom +vacation +a lot, lot +un alunno +bar +vinte e un +auto's, auto diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.test b/extensions/spellcheck/hunspell/tests/unit/data/rep.test new file mode 100644 index 000000000..dc295077f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i ISO8859-1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong b/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong new file mode 100644 index 000000000..cd9699c4c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/rep.wrong @@ -0,0 +1,11 @@ +phorm +fantom +vacashun +vacashuns +alot +un'alunno +foo +foobars +barfoos +vinten +autos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff b/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff new file mode 100644 index 000000000..ac434a426 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.aff @@ -0,0 +1,9 @@ +# With REP suggestions, we can fix typical language specific misspellings. + +SET UTF-8 + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 + +REP 1 +REP oo őő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic b/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic new file mode 100644 index 000000000..1890fcb8e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.dic @@ -0,0 +1,2 @@ +1 +főő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug b/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug new file mode 100644 index 000000000..8a00bc371 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.sug @@ -0,0 +1 @@ +főő diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.test b/extensions/spellcheck/hunspell/tests/unit/data/reputf.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/reputf.wrong @@ -0,0 +1 @@ +foo diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff new file mode 100644 index 000000000..3ab347319 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.aff @@ -0,0 +1,8 @@ +# Forbid compound word with triple letters +CHECKCOMPOUNDTRIPLE +# Allow simplified forms +SIMPLIFIEDTRIPLE + +COMPOUNDMIN 2 + +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic new file mode 100644 index 000000000..cfe7a35dc --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.dic @@ -0,0 +1,3 @@ +2 +glass/A +sko/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good new file mode 100644 index 000000000..23a4815e8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.good @@ -0,0 +1,3 @@ +glass +sko +glassko diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong new file mode 100644 index 000000000..281128768 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/simplifiedtriple.wrong @@ -0,0 +1 @@ +glasssko diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.aff b/extensions/spellcheck/hunspell/tests/unit/data/slash.aff new file mode 100644 index 000000000..6ab104b9e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.aff @@ -0,0 +1,4 @@ +# slashes in words (\/) + +# (only for tokenization) +WORDCHARS /: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.dic b/extensions/spellcheck/hunspell/tests/unit/data/slash.dic new file mode 100644 index 000000000..478276df6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.dic @@ -0,0 +1,5 @@ +4 +/ +1\/2 +http:\/\/ +\/usr\/share\/myspell\/ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.good b/extensions/spellcheck/hunspell/tests/unit/data/slash.good new file mode 100644 index 000000000..4a25e205f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.good @@ -0,0 +1,4 @@ +/ +1/2 +http:// +/usr/share/myspell/ diff --git a/extensions/spellcheck/hunspell/tests/unit/data/slash.test b/extensions/spellcheck/hunspell/tests/unit/data/slash.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/slash.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.aff b/extensions/spellcheck/hunspell/tests/unit/data/sug.aff new file mode 100644 index 000000000..b1f2adba6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.aff @@ -0,0 +1,15 @@ +# new suggestion methods of Hunspell 1.5: +# capitalization: nasa -> NASA +# long swap: permenant -> permanent +# long mov: Ghandi -> Gandhi +# double two characters: vacacation -> vacation +# space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) + +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 +REP 1 +REP alot a_lot +KEY qwertzuiop|asdfghjkl|yxcvbnm|aq +WORDCHARS . +FORBIDDENWORD ? + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.dic b/extensions/spellcheck/hunspell/tests/unit/data/sug.dic new file mode 100644 index 000000000..0c22cedf4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.dic @@ -0,0 +1,11 @@ +1 +NASA +Gandhi +grateful +permanent +vacation +a +lot +have +which +McDonald diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.sug b/extensions/spellcheck/hunspell/tests/unit/data/sug.sug new file mode 100644 index 000000000..e277bdb77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.sug @@ -0,0 +1,12 @@ +NASA +Gandhi +grateful +permanent +vacation +a lot, lot +permanent. Vacation +have +which +Gandhi +McDonald +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.test b/extensions/spellcheck/hunspell/tests/unit/data/sug.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong b/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong new file mode 100644 index 000000000..4d184d5a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sug.wrong @@ -0,0 +1,12 @@ +nasa +Ghandi +greatful +permenant +vacacation +alot +permanent.Vacation +ahev +hwihc +GAndhi +Mcdonald +permqnent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt new file mode 100644 index 000000000..571f3796a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/List_of_common_misspellings.txt @@ -0,0 +1,4020 @@ +# source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines +abandonned abandoned +aberation aberration +abilties abilities +abilty ability +abondon abandon +abondoned abandoned +abondoning abandoning +abondons abandons +aborigene aborigine +abortificant abortifacient +abreviated abbreviated +abreviation abbreviation +abritrary arbitrary +absense absence +absolutly absolutely +absorbsion absorption +absorbtion absorption +abundacies abundances +abundancies abundances +abundunt abundant +abutts abuts +acadamy academy +acadmic academic +accademic academic +accademy academy +acccused accused +accelleration acceleration +accension accession, ascension +acceptence acceptance +acceptible acceptable +accessable accessible +accidentaly accidentally +accidently accidentally +acclimitization acclimatization +acommodate accommodate +accomadate accommodate +accomadated accommodated +accomadates accommodates +accomadating accommodating +accomadation accommodation +accomadations accommodations +accomdate accommodate +accomodate accommodate +accomodated accommodated +accomodates accommodates +accomodating accommodating +accomodation accommodation +accomodations accommodations +accompanyed accompanied +accordeon accordion +accordian accordion +accoring according +accoustic acoustic +accquainted acquainted +accross across +accussed accused +acedemic academic +acheive achieve +acheived achieved +acheivement achievement +acheivements achievements +acheives achieves +acheiving achieving +acheivment achievement +acheivments achievements +achievment achievement +achievments achievements +achive achieve, archive +achived achieved, archived +achivement achievement +achivements achievements +acknowldeged acknowledged +acknowledgeing acknowledging +ackward awkward, backward +acomplish accomplish +acomplished accomplished +acomplishment accomplishment +acomplishments accomplishments +acording according +acordingly accordingly +acquaintence acquaintance +acquaintences acquaintances +acquiantence acquaintance +acquiantences acquaintances +acquited acquitted +activites activities +activly actively +actualy actually +acuracy accuracy +acused accused +acustom accustom +acustommed accustomed +adavanced advanced +adbandon abandon +additinally additionally +additionaly additionally +addmission admission +addopt adopt +addopted adopted +addoptive adoptive +addres address, adders +addresable addressable +addresed addressed +addresing addressing +addressess addresses +addtion addition +addtional additional +adecuate adequate +adhearing adhering +adherance adherence +admendment amendment +admininistrative administrative +adminstered administered +adminstrate administrate +adminstration administration +adminstrative administrative +adminstrator administrator +admissability admissibility +admissable admissible +admited admitted +admitedly admittedly +adn and +adolecent adolescent +adquire acquire +adquired acquired +adquires acquires +adquiring acquiring +adres address +adresable addressable +adresing addressing +adress address +adressable addressable +adressed addressed +adressing addressing, dressing +adventrous adventurous +advertisment advertisement +advertisments advertisements +advesary adversary +adviced advised +aeriel aerial +aeriels aerials +afair affair +afficianados aficionados +afficionado aficionado +afficionados aficionados +affilate affiliate +affilliate affiliate +affort afford, effort +aforememtioned aforementioned +againnst against +agains against +agaisnt against +aganist against +aggaravates aggravates +aggreed agreed +aggreement agreement +aggregious egregious +aggresive aggressive +agian again +agianst against +agin again +agina again, angina +aginst against +agravate aggravate +agre agree +agred agreed +agreeement agreement +agreemnt agreement +agregate aggregate +agregates aggregates +agreing agreeing +agression aggression +agressive aggressive +agressively aggressively +agressor aggressor +agricuture agriculture +agrieved aggrieved +ahev have +ahppen happen +ahve have +aicraft aircraft +aiport airport +airbourne airborne +aircaft aircraft +aircrafts aircraft +airporta airports +airrcraft aircraft +aisian asian +albiet albeit +alchohol alcohol +alchoholic alcoholic +alchol alcohol +alcholic alcoholic +alcohal alcohol +alcoholical alcoholic +aledge allege +aledged alleged +aledges alleges +alege allege +aleged alleged +alegience allegiance +algebraical algebraic +algorhitms algorithms +algoritm algorithm +algoritms algorithms +alientating alienating +alledge allege +alledged alleged +alledgedly allegedly +alledges alleges +allegedely allegedly +allegedy allegedly +allegely allegedly +allegence allegiance +allegience allegiance +allign align +alligned aligned +alliviate alleviate +allopone allophone +allopones allophones +allready already +allthough although +alltime all-time +alltogether altogether +almsot almost +alochol alcohol +alomst almost +alot a lot, allot +alotted allotted +alowed allowed +alowing allowing +alreayd already +alse else +alsot also +alternitives alternatives +altho although +althought although +altough although +alusion allusion, illusion +alwasy always +alwyas always +amalgomated amalgamated +amatuer amateur +amature armature, amateur +amendmant amendment +amerliorate ameliorate +amke make +amking making +ammend amend +ammended amended +ammendment amendment +ammendments amendments +ammount amount +ammused amused +amoung among +amoungst amongst +amung among +analagous analogous +analitic analytic +analogeous analogous +anarchim anarchism +anarchistm anarchism +anbd and +ancestory ancestry +ancilliary ancillary +androgenous androgynous +androgeny androgyny +anihilation annihilation +aniversary anniversary +annoint anoint +annointed anointed +annointing anointing +annoints anoints +annouced announced +annualy annually +annuled annulled +anohter another +anomolies anomalies +anomolous anomalous +anomoly anomaly +anonimity anonymity +anounced announced +ansalisation nasalisation +ansalization nasalization +ansestors ancestors +antartic antarctic +anthromorphization anthropomorphization +anual annual, anal +anulled annulled +anwsered answered +anyhwere anywhere +anyother any other +anytying anything +aparent apparent +aparment apartment +apenines apennines, Apennines +aplication application +aplied applied +apolegetics apologetics +apon upon, apron +apparant apparent +apparantly apparently +appart apart +appartment apartment +appartments apartments +appealling appealing, appalling +appeareance appearance +appearence appearance +appearences appearances +appenines apennines, Apennines +apperance appearance +apperances appearances +applicaiton application +applicaitons applications +appologies apologies +appology apology +apprearance appearance +apprieciate appreciate +approachs approaches +appropiate appropriate +appropraite appropriate +appropropiate appropriate +approproximate approximate +approxamately approximately +approxiately approximately +approximitely approximately +aprehensive apprehensive +apropriate appropriate +aproximate approximate +aproximately approximately +aquaintance acquaintance +aquainted acquainted +aquiantance acquaintance +aquire acquire +aquired acquired +aquiring acquiring +aquisition acquisition +aquitted acquitted +aranged arranged +arangement arrangement +arbitarily arbitrarily +arbitary arbitrary +archaelogists archaeologists +archaelogy archaeology +archaoelogy archeology, archaeology +archaology archeology, archaeology +archeaologist archeologist, archaeologist +archeaologists archeologists, archaeologists +archetect architect +archetects architects +archetectural architectural +archetecturally architecturally +archetecture architecture +archiac archaic +archictect architect +archimedian archimedean +architechturally architecturally +architechture architecture +architechtures architectures +architectual architectural +archtype archetype +archtypes archetypes +aready already +areodynamics aerodynamics +argubly arguably +arguement argument +arguements arguments +arised arose +arival arrival +armamant armament +armistace armistice +aroud around +arrangment arrangement +arrangments arrangements +arround around +artical article +artice article +articel article +artifical artificial +artifically artificially +artillary artillery +arund around +asetic ascetic +asign assign +aslo also +asociated associated +asorbed absorbed +asphyxation asphyxiation +assasin assassin +assasinate assassinate +assasinated assassinated +assasinates assassinates +assasination assassination +assasinations assassinations +assasined assassinated +assasins assassins +assassintation assassination +assemple assemble +assertation assertion +asside aside +assisnate assassinate +assit assist +assitant assistant +assocation association +assoicate associate +assoicated associated +assoicates associates +assosication assassination +asssassans assassins +assualt assault +assualted assaulted +assymetric asymmetric +assymetrical asymmetrical +asteriod asteroid +asthetic aesthetic +asthetical aesthetical +asthetically aesthetically +asume assume +aswell as well +atain attain +atempting attempting +atheistical atheistic +athenean athenian +atheneans athenians +athiesm atheism +athiest atheist +atorney attorney +atribute attribute +atributed attributed +atributes attributes +attaindre attainder, attained +attemp attempt +attemped attempted +attemt attempt +attemted attempted +attemting attempting +attemts attempts +attendence attendance +attendent attendant +attendents attendants +attened attended +attension attention +attitide attitude +attributred attributed +attrocities atrocities +audeince audience +auromated automated +austrailia Australia +austrailian Australian +auther author +authobiographic autobiographic +authobiography autobiography +authorative authoritative +authorites authorities +authorithy authority +authoritiers authorities +authoritive authoritative +authrorities authorities +autochtonous autochthonous +autoctonous autochthonous +automaticly automatically +automibile automobile +automonomous autonomous +autor author +autority authority +auxilary auxiliary +auxillaries auxiliaries +auxillary auxiliary +auxilliaries auxiliaries +auxilliary auxiliary +availablity availability +availaible available +availble available +availiable available +availible available +avalable available +avalance avalanche +avaliable available +avation aviation +avengence a vengeance +averageed averaged +avilable available +awared awarded +awya away +baceause because +backgorund background +backrounds backgrounds +bakc back +banannas bananas +bandwith bandwidth +bankrupcy bankruptcy +banruptcy bankruptcy +baout about, bout +basicaly basically +basicly basically +bcak back +beachead beachhead +beacuse because +beastiality bestiality +beatiful beautiful +beaurocracy bureaucracy +beaurocratic bureaucratic +beautyfull beautiful +becamae became +becasue because +beccause because +becomeing becoming +becomming becoming +becouse because +becuase because +bedore before +befoer before +beggin begin, begging +begginer beginner +begginers beginners +beggining beginning +begginings beginnings +beggins begins +begining beginning +beginnig beginning +behavour behavior, behaviour +beleagured beleaguered +beleif belief +beleive believe +beleived believed +beleives believes +beleiving believing +beligum belgium +belive believe +belived believed +belives believes, beliefs +belligerant belligerent +bellweather bellwether +bemusemnt bemusement +beneficary beneficiary +beng being +benificial beneficial +benifit benefit +benifits benefits +bergamont bergamot +Bernouilli Bernoulli +beseige besiege +beseiged besieged +beseiging besieging +betwen between +beween between +bewteen between +bilateraly bilaterally +billingualism bilingualism +binominal binomial +bizzare bizarre +blaim blame +blaimed blamed +blessure blessing +Blitzkreig Blitzkrieg +boaut bout, boat, about +bodydbuilder bodybuilder +bombardement bombardment +bombarment bombardment +bondary boundary +Bonnano Bonanno +borke broke +boundry boundary +bouyancy buoyancy +bouyant buoyant +boyant buoyant +Brasillian Brazilian +breakthough breakthrough +breakthroughts breakthroughs +breif brief +breifly briefly +brethen brethren +bretheren brethren +briliant brilliant +brillant brilliant +brimestone brimstone +Britian Britain +Brittish British +broacasted broadcast +broadacasting broadcasting +broady broadly +Buddah Buddha +buisness business +buisnessman businessman +buoancy buoyancy +buring burying, burning, burin, during +burried buried +busineses business, businesses +busness business +bussiness business +cacuses caucuses +cahracters characters +calaber caliber +calander calendar, calender, colander +calculs calculus +calenders calendars +caligraphy calligraphy +caluclate calculate +caluclated calculated +caluculate calculate +caluculated calculated +calulate calculate +calulated calculated +Cambrige Cambridge +camoflage camouflage +campain campaign +campains campaigns +candadate candidate +candiate candidate +candidiate candidate +cannister canister +cannisters canisters +cannnot cannot +cannonical canonical +cannotation connotation +cannotations connotations +cant cannot, can not, can't +caost coast +caperbility capability +Capetown Cape Town +capible capable +captial capital +captued captured +capturd captured +carachter character +caracterized characterized +carcas carcass, Caracas +carefull careful +careing caring +carismatic charismatic +Carmalite Carmelite +carmel caramel, carmel-by-the-sea +carniverous carnivorous +carreer career +carrers careers +Carribbean Caribbean +Carribean Caribbean +cartdridge cartridge +Carthagian Carthaginian +carthographer cartographer +cartilege cartilage +cartilidge cartilage +cartrige cartridge +casette cassette +casion caisson +cassawory cassowary +cassowarry cassowary +casulaties casualties +casulaty casualty +catagories categories +catagorized categorized +catagory category +catergorize categorize +catergorized categorized +Cataline Catiline, Catalina +cathlic catholic +catholocism catholicism +catterpilar caterpillar +catterpilars caterpillars +cattleship battleship +causalities casualties +Ceasar Caesar +Celcius Celsius +cellpading cellpadding +cementary cemetery +cemetarey cemetery +cemetaries cemeteries +cemetary cemetery +cencus census +censur censor, censure +cententenial centennial +centruies centuries +centruy century +ceratin certain, keratin +cerimonial ceremonial +cerimonies ceremonies +cerimonious ceremonious +cerimony ceremony +ceromony ceremony +certainity certainty +certian certain +cervial cervical, servile, serval +chalenging challenging +challange challenge +challanged challenged +challege challenge +Champange Champagne +changable changeable +charachter character +charactor character +charachters characters +charactersistic characteristic +charactors characters +charasmatic charismatic +charaterized characterized +chariman chairman +charistics characteristics +chasr chaser, chase +cheif chief +chemcial chemical +chemcially chemically +chemestry chemistry +chemicaly chemically +childbird childbirth +childen children +choosen chosen +chracter character +chuch church +churchs churches +Cincinatti Cincinnati +Cincinnatti Cincinnati +circulaton circulation +circumsicion circumcision +circut circuit +ciricuit circuit +ciriculum curriculum +civillian civilian +claer clear +claerer clearer +claerly clearly +claimes claims +clas class +clasic classic +clasical classical +clasically classically +cleareance clearance +clera clear, sclera +clincial clinical +clinicaly clinically +cmo com +cmoputer computer +co-incided coincided +coctail cocktail +coform conform +cognizent cognizant +coincedentally coincidentally +colaborations collaborations +colateral collateral +colelctive collective +collaberative collaborative +collecton collection +collegue colleague +collegues colleagues +collonade colonnade +collonies colonies +collony colony +collosal colossal +colonizators colonizers +comander commander, commandeer +comando commando +comandos commandos +comany company +comapany company +comback comeback +combanations combinations +combinatins combinations +combusion combustion +comdemnation condemnation +comemmorates commemorates +comemoretion commemoration +comision commission +comisioned commissioned +comisioner commissioner +comisioning commissioning +comisions commissions +comission commission +comissioned commissioned +comissioner commissioner +comissioning commissioning +comissions commissions +comited committed +comiting committing +comitted committed +comittee committee +comitting committing +commandoes commandos +commedic comedic +commemerative commemorative +commemmorate commemorate +commemmorating commemorating +commerical commercial +commerically commercially +commericial commercial +commericially commercially +commerorative commemorative +comming coming +comminication communication +commision commission +commisioned commissioned +commisioner commissioner +commisioning commissioning +commisions commissions +commited committed +commitee committee +commiting committing +committe committee +committment commitment +committments commitments +commmemorated commemorated +commongly commonly +commonweath commonwealth +commuications communications +commuinications communications +communciation communication +communiation communication +communites communities +compability compatibility +comparision comparison +comparisions comparisons +comparitive comparative +comparitively comparatively +compatabilities compatibilities +compatability compatibility +compatable compatible +compatablities compatibilities +compatablity compatibility +compatiable compatible +compatiblities compatibilities +compatiblity compatibility +compeitions competitions +compensantion compensation +competance competence +competant competent +competative competitive +competion competition, completion +competitiion competition +competive competitive +competiveness competitiveness +comphrehensive comprehensive +compitent competent +completedthe completed the +completelyl completely +completetion completion +complier compiler +componant component +comprable comparable +comprimise compromise +compulsary compulsory +compulsery compulsory +computarized computerized +concensus consensus +concider consider +concidered considered +concidering considering +conciders considers +concieted conceited +concieved conceived +concious conscious +conciously consciously +conciousness consciousness +condamned condemned +condemmed condemned +condidtion condition +condidtions conditions +conditionsof conditions of +conected connected +conection connection +conesencus consensus +confidental confidential +confidentally confidentially +confids confides +configureable configurable +confortable comfortable +congradulations congratulations +congresional congressional +conived connived +conjecutre conjecture +conjuction conjunction +Conneticut Connecticut +conotations connotations +conquerd conquered +conquerer conqueror +conquerers conquerors +conqured conquered +conscent consent +consciouness consciousness +consdider consider +consdidered considered +consdiered considered +consectutive consecutive +consenquently consequently +consentrate concentrate +consentrated concentrated +consentrates concentrates +consept concept +consequentually consequently +consequeseces consequences +consern concern +conserned concerned +conserning concerning +conservitive conservative +consiciousness consciousness +consicousness consciousness +considerd considered +consideres considered +consious conscious +consistant consistent +consistantly consistently +consituencies constituencies +consituency constituency +consituted constituted +consitution constitution +consitutional constitutional +consolodate consolidate +consolodated consolidated +consonent consonant +consonents consonants +consorcium consortium +conspiracys conspiracies +conspiriator conspirator +constaints constraints +constanly constantly +constarnation consternation +constatn constant +constinually continually +constituant constituent +constituants constituents +constituion constitution +constituional constitutional +consttruction construction +constuction construction +consulant consultant +consumate consummate +consumated consummated +contaiminate contaminate +containes contains +contamporaries contemporaries +contamporary contemporary +contempoary contemporary +contemporaneus contemporaneous +contempory contemporary +contendor contender +contined continued +continous continuous +continously continuously +continueing continuing +contravercial controversial +contraversy controversy +contributer contributor +contributers contributors +contritutions contributions +controled controlled +controling controlling +controll control +controlls controls +controvercial controversial +controvercy controversy +controveries controversies +controversal controversial +controversey controversy +controvertial controversial +controvery controversy +contruction construction +conveinent convenient +convenant covenant +convential conventional +convertables convertibles +convertion conversion +conveyer conveyor +conviced convinced +convienient convenient +coordiantion coordination +coorperation cooperation, corporation +coorperations corporations +copmetitors competitors +coputer computer +copywrite copyright +coridal cordial +cornmitted committed +corosion corrosion +corparate corporate +corperations corporations +correcters correctors +correponding corresponding +correposding corresponding +correspondant correspondent +correspondants correspondents +corridoors corridors +corrispond correspond +corrispondant correspondent +corrispondants correspondents +corrisponded corresponded +corrisponding corresponding +corrisponds corresponds +costitution constitution +coucil council +coudl could, cloud +councellor councillor, counselor, councilor +councellors councillors, counselors, councilors +counries countries +countains contains +countires countries +coururier courier, couturier +coverted converted, covered, coveted +cpoy coy, copy +creaeted created +creedence credence +critereon criterion +criterias criteria +criticists critics +critising criticising, criticizing +critisising criticising +critisism criticism +critisisms criticisms +critisize criticise, criticize +critisized criticised, criticized +critisizes criticises, criticizes +critisizing criticising, criticizing +critized criticized +critizing criticizing +crockodiles crocodiles +crowm crown +crtical critical +crticised criticised +crucifiction crucifixion +crusies cruises +crystalisation crystallisation +culiminating culminating +cumulatative cumulative +curch church +curcuit circuit +currenly currently +curriculem curriculum +cxan cyan +cyclinder cylinder +dael deal, dial, dahl +dalmation dalmatian +damenor demeanor +Dardenelles Dardanelles +dacquiri daiquiri +debateable debatable +decendant descendant +decendants descendants +decendent descendant +decendents descendants +decideable decidable +decidely decidedly +decieved deceived +decison decision +decomissioned decommissioned +decomposit decompose +decomposited decomposed +decompositing decomposing +decomposits decomposes +decress decrees +decribe describe +decribed described +decribes describes +decribing describing +dectect detect +defendent defendant +defendents defendants +deffensively defensively +deffine define +deffined defined +definance defiance +definate definite +definately definitely +definatly definitely +definetly definitely +definining defining +definit definite +definitly definitely +definiton definition +defintion definition +degrate degrade +delagates delegates +delapidated dilapidated +delerious delirious +delevopment development +deliberatly deliberately +delusionally delusively +demenor demeanor +demographical demographic +demolision demolition +demorcracy democracy +demostration demonstration +denegrating denigrating +densly densely +deparment department +deparments departments +deparmental departmental +dependance dependence +dependancy dependency +dependant dependent +deram dram, dream +deriviated derived +derivitive derivative +derogitory derogatory +descendands descendants +descibed described +descision decision +descisions decisions +descriibes describes +descripters descriptors +descripton description +desctruction destruction +descuss discuss +desgined designed +deside decide +desigining designing +desinations destinations +desintegrated disintegrated +desintegration disintegration +desireable desirable +desitned destined +desktiop desktop +desorder disorder +desoriented disoriented +desparate desperate, disparate +despatched dispatched +despict depict +despiration desperation +dessicated desiccated +dessigned designed +destablized destabilized +destory destroy +detailled detailed +detatched detached +deteoriated deteriorated +deteriate deteriorate +deterioriating deteriorating +determinining determining +detremental detrimental +devasted devastated +develope develop +developement development +developped developed +develpment development +devels delves +devestated devastated +devestating devastating +devide divide +devided divided +devistating devastating +devolopement development +diablical diabolical +diamons diamonds +diaster disaster +dichtomy dichotomy +diconnects disconnects +dicover discover +dicovered discovered +dicovering discovering +dicovers discovers +dicovery discovery +dicussed discussed +didnt didn't +diea idea, die +dieing dying, dyeing +dieties deities +diety deity +diferent different +diferrent different +differentiatiations differentiations +differnt different +difficulity difficulty +diffrent different +dificulties difficulties +dificulty difficulty +dimenions dimensions +dimention dimension +dimentional dimensional +dimentions dimensions +dimesnional dimensional +diminuitive diminutive +diosese diocese +diphtong diphthong +diphtongs diphthongs +diplomancy diplomacy +dipthong diphthong +dipthongs diphthongs +dirived derived +disagreeed disagreed +disapeared disappeared +disapointing disappointing +disappearred disappeared +disaproval disapproval +disasterous disastrous +disatisfaction dissatisfaction +disatisfied dissatisfied +disatrous disastrous +discontentment discontent +discribe describe +discribed described +discribes describes +discribing describing +disctinction distinction +disctinctive distinctive +disemination dissemination +disenchanged disenchanted +disiplined disciplined +disobediance disobedience +disobediant disobedient +disolved dissolved +disover discover +dispair despair +disparingly disparagingly +dispence dispense +dispenced dispensed +dispencing dispensing +dispicable despicable +dispite despite +dispostion disposition +disproportiate disproportionate +disputandem disputandum +disricts districts +dissagreement disagreement +dissapear disappear +dissapearance disappearance +dissapeared disappeared +dissapearing disappearing +dissapears disappears +dissappear disappear +dissappears disappears +dissappointed disappointed +dissarray disarray +dissobediance disobedience +dissobediant disobedient +dissobedience disobedience +dissobedient disobedient +distiction distinction +distingish distinguish +distingished distinguished +distingishes distinguishes +distingishing distinguishing +distingquished distinguished +distrubution distribution +distruction destruction +distructive destructive +ditributed distributed +diversed diverse, diverged +divice device +divison division +divisons divisions +doccument document +doccumented documented +doccuments documents +docrines doctrines +doctines doctrines +documenatry documentary +doens does +doesnt doesn't +doign doing +dominaton domination +dominent dominant +dominiant dominant +donig doing +dosen't doesn't +doub doubt, daub +doulbe double +dowloads downloads +dramtic dramatic +draughtman draughtsman +Dravadian Dravidian +dreasm dreams +driectly directly +drnik drink +druming drumming +drummless drumless +dupicate duplicate +durig during +durring during +duting during +dyas dryas +eahc each +ealier earlier +earlies earliest +earnt earned +ecclectic eclectic +eceonomy economy +ecidious deciduous +eclispe eclipse +ecomonic economic +ect etc +eearly early +efel evil +effeciency efficiency +effecient efficient +effeciently efficiently +efficency efficiency +efficent efficient +efficently efficiently +efford effort, afford +effords efforts, affords +effulence effluence +eigth eighth, eight +eiter either +elction election +electic eclectic, electric +electon election, electron +electrial electrical +electricly electrically +electricty electricity +elementay elementary +eleminated eliminated +eleminating eliminating +eles eels +eletricity electricity +elicided elicited +eligable eligible +elimentary elementary +ellected elected +elphant elephant +embarass embarrass +embarassed embarrassed +embarassing embarrassing +embarassment embarrassment +embargos embargoes +embarras embarrass +embarrased embarrassed +embarrasing embarrassing +embarrasment embarrassment +embezelled embezzled +emblamatic emblematic +eminate emanate +eminated emanated +emision emission +emited emitted +emiting emitting +emition emission, emotion +emmediately immediately +emmigrated emigrated +emminent eminent, imminent +emminently eminently +emmisaries emissaries +emmisarries emissaries +emmisarry emissary +emmisary emissary +emmision emission +emmisions emissions +emmited emitted +emmiting emitting +emmitted emitted +emmitting emitting +emnity enmity +emperical empirical +emphaised emphasised +emphsis emphasis +emphysyma emphysema +empirial empirical, imperial +emprisoned imprisoned +enameld enameled +enchancement enhancement +encouraing encouraging +encryptiion encryption +encylopedia encyclopedia +endevors endeavors +endevour endeavour +endig ending +endolithes endoliths +enduce induce +ened need +enflamed inflamed +enforceing enforcing +engagment engagement +engeneer engineer +engeneering engineering +engieneer engineer +engieneers engineers +enlargment enlargement +enlargments enlargements +Enlish English, enlist +enourmous enormous +enourmously enormously +ensconsed ensconced +entaglements entanglements +enteratinment entertainment +entitity entity +entitlied entitled +entrepeneur entrepreneur +entrepeneurs entrepreneurs +enviorment environment +enviormental environmental +enviormentally environmentally +enviorments environments +enviornment environment +enviornmental environmental +enviornmentalist environmentalist +enviornmentally environmentally +enviornments environments +enviroment environment +enviromental environmental +enviromentalist environmentalist +enviromentally environmentally +enviroments environments +envolutionary evolutionary +envrionments environments +enxt next +epidsodes episodes +epsiode episode +equialent equivalent +equilibium equilibrium +equilibrum equilibrium +equiped equipped +equippment equipment +equitorial equatorial +equivelant equivalent +equivelent equivalent +equivilant equivalent +equivilent equivalent +equivlalent equivalent +erally orally, really +eratic erratic +eratically erratically +eraticly erratically +erested arrested, erected +errupted erupted +esential essential +esitmated estimated +esle else +especialy especially +essencial essential +essense essence +essentail essential +essentialy essentially +essentual essential +essesital essential +estabishes establishes +establising establishing +ethnocentricm ethnocentrism +ethose those, ethos +Europian European +Europians Europeans +Eurpean European +Eurpoean European +evenhtually eventually +eventally eventually +eventially eventually +eventualy eventually +everthing everything +everytime every time +everyting everything +eveyr every +evidentally evidently +exagerate exaggerate +exagerated exaggerated +exagerates exaggerates +exagerating exaggerating +exagerrate exaggerate +exagerrated exaggerated +exagerrates exaggerates +exagerrating exaggerating +examinated examined +exampt exempt +exapansion expansion +excact exact +excange exchange +excecute execute +excecuted executed +excecutes executes +excecuting executing +excecution execution +excedded exceeded +excelent excellent +excell excel +excellance excellence +excellant excellent +excells excels +excercise exercise +exchanching exchanging +excisted existed +exculsivly exclusively +execising exercising +exection execution +exectued executed +exeedingly exceedingly +exelent excellent +exellent excellent +exemple example +exept except +exeptional exceptional +exerbate exacerbate +exerbated exacerbated +exerciese exercises +exerpt excerpt +exerpts excerpts +exersize exercise +exerternal external +exhalted exalted +exhibtion exhibition +exibition exhibition +exibitions exhibitions +exicting exciting +exinct extinct +existance existence +existant existent +existince existence +exliled exiled +exludes excludes +exmaple example +exonorate exonerate +exoskelaton exoskeleton +expalin explain +expeced expected +expecially especially +expeditonary expeditionary +expeiments experiments +expell expel +expells expels +experiance experience +experianced experienced +expiditions expeditions +expierence experience +explaination explanation +explaning explaining +explictly explicitly +exploititive exploitative +explotation exploitation +expropiated expropriated +expropiation expropriation +exressed expressed +extemely extremely +extention extension +extentions extensions +extered exerted +extermist extremist +extint extinct, extant +extradiction extradition +extraterrestial extraterrestrial +extraterrestials extraterrestrials +extravagent extravagant +extrememly extremely +extremeophile extremophile +extremly extremely +extrordinarily extraordinarily +extrordinary extraordinary +eyar year, eyas +eyars years, eyas +eyasr years, eyas +faciliate facilitate +faciliated facilitated +faciliates facilitates +facilites facilities +facillitate facilitate +facinated fascinated +facist fascist +familes families +familliar familiar +famoust famous +fanatism fanaticism +Farenheit Fahrenheit +fatc fact +faught fought +favoutrable favourable +feasable feasible +Febuary February +fedreally federally +feromone pheromone +fertily fertility +fianite finite +fianlly finally +ficticious fictitious +fictious fictitious +fidn find +fiel feel, field, file, phial +fiels feels, fields, files, phials +fiercly fiercely +fightings fighting +filiament filament +fimilies families +finacial financial +finaly finally +financialy financially +firends friends +firts flirts, first +fisionable fissionable +flamable flammable +flawess flawless +fleed fled, freed +Flemmish Flemish +florescent fluorescent +flourescent fluorescent +fluorish flourish +follwoing following +folowing following +fomed formed +fomr from, form +fonetic phonetic +fontrier fontier +foootball football +forbad forbade +forbiden forbidden +foreward foreword +forfiet forfeit +forhead forehead +foriegn foreign +Formalhaut Fomalhaut +formallize formalize +formallized formalized +formaly formally +formelly formerly +formidible formidable +formost foremost +forsaw foresaw +forseeable foreseeable +fortelling foretelling +forunner forerunner +foucs focus +foudn found +fougth fought +foundaries foundries +foundary foundry +Foundland Newfoundland +fourties forties +fourty forty +fouth fourth +foward forward +fucntion function +fucntioning functioning +Fransiscan Franciscan +Fransiscans Franciscans +freind friend +freindly friendly +frequentily frequently +frome from +fromed formed +froniter frontier +fufill fulfill +fufilled fulfilled +fulfiled fulfilled +fundametal fundamental +fundametals fundamentals +funguses fungi +funtion function +furuther further +futher further +futhermore furthermore +futhroc futhark, futhorc +gae game, Gael, gale +galatic galactic +Galations Galatians +gallaxies galaxies +galvinized galvanized +Gameboy Game Boy +ganerate generate +ganes games +ganster gangster +garantee guarantee +garanteed guaranteed +garantees guarantees +garnison garrison +gauarana guaraná +gaurantee guarantee +gauranteed guaranteed +gaurantees guarantees +gaurd guard, gourd +gaurentee guarantee +gaurenteed guaranteed +gaurentees guarantees +geneological genealogical +geneologies genealogies +geneology genealogy +generaly generally +generatting generating +genialia genitalia +geographicial geographical +geometrician geometer +geometricians geometers +gerat great +Ghandi Gandhi +glight flight +gnawwed gnawed +godess goddess +godesses goddesses +Godounov Godunov +gogin going, Gauguin +goign going +gonig going +Gothenberg Gothenburg +Gottleib Gottlieb +gouvener governor +govement government +govenment government +govenrment government +goverance governance +goverment government +govermental governmental +governer governor +governmnet government +govorment government +govormental governmental +govornment government +gracefull graceful +graet great +grafitti graffiti +gramatically grammatically +grammaticaly grammatically +grammer grammar +grat great +gratuitious gratuitous +greatful grateful +greatfully gratefully +greif grief +gridles griddles +gropu group +grwo grow +Guaduloupe Guadalupe, Guadeloupe +Guadulupe Guadalupe, Guadeloupe +guage gauge +guarentee guarantee +guarenteed guaranteed +guarentees guarantees +Guatamala Guatemala +Guatamalan Guatemalan +guerilla guerrilla +guerillas guerrillas +guerrila guerrilla +guerrilas guerrillas +guidence guidance +Guilia Giulia +Guilio Giulio +Guiness Guinness +Guiseppe Giuseppe +gunanine guanine +gurantee guarantee +guranteed guaranteed +gurantees guarantees +guttaral guttural +gutteral guttural +habaeus habeas +habeus habeas +Habsbourg Habsburg +haemorrage haemorrhage +haev have, heave +Hallowean Hallowe'en, Halloween +halp help +hapen happen +hapened happened +hapening happening +happend happened +happended happened +happenned happened +harased harassed +harases harasses +harasment harassment +harasments harassments +harassement harassment +harras harass +harrased harassed +harrases harasses +harrasing harassing +harrasment harassment +harrasments harassments +harrassed harassed +harrasses harassed +harrassing harassing +harrassment harassment +harrassments harassments +hasnt hasn't +haviest heaviest +headquater headquarter +headquarer headquarter +headquatered headquartered +headquaters headquarters +healthercare healthcare +heared heard +heathy healthy +Heidelburg Heidelberg +heigher higher +heirarchy hierarchy +heiroglyphics hieroglyphics +helment helmet +helpfull helpful +helpped helped +hemmorhage hemorrhage +herad heard, Hera +heridity heredity +heroe hero +heros heroes +hertzs hertz +hesistant hesitant +heterogenous heterogeneous +hieght height +hierachical hierarchical +hierachies hierarchies +hierachy hierarchy +hierarcical hierarchical +hierarcy hierarchy +hieroglph hieroglyph +hieroglphs hieroglyphs +higer higher +higest highest +higway highway +hillarious hilarious +himselv himself +hinderance hindrance +hinderence hindrance +hindrence hindrance +hipopotamus hippopotamus +hismelf himself +histocompatability histocompatibility +historicians historians +hitsingles hit singles +holliday holiday +homestate home state +homogeneize homogenize +homogeneized homogenized +honory honorary +horrifing horrifying +hosited hoisted +hospitible hospitable +hounour honour +housr hours, house +howver however +hsitorians historians +hstory history +hten then, hen, the +htere there, here +htey they +htikn think +hting thing +htink think +htis this +humer humor, humour +humerous humorous, humerus +huminoid humanoid +humoural humoral +humurous humorous +husban husband +hvae have +hvaing having +hvea have, heave +hwihc which +hwile while +hwole whole +hydogen hydrogen +hydropile hydrophile +hydropilic hydrophilic +hydropobe hydrophobe +hydropobic hydrophobic +hygeine hygiene +hypocracy hypocrisy +hypocrasy hypocrisy +hypocricy hypocrisy +hypocrit hypocrite +hypocrits hypocrites +iconclastic iconoclastic +idaeidae idea +idaes ideas +idealogies ideologies +idealogy ideology +identicial identical +identifers identifiers +ideosyncratic idiosyncratic +idesa ideas, ides +idiosyncracy idiosyncrasy +Ihaca Ithaca +illegimacy illegitimacy +illegitmate illegitimate +illess illness +illiegal illegal +illution illusion +ilness illness +ilogical illogical +imagenary imaginary +imagin imagine +imaginery imaginary, imagery +imanent eminent, imminent +imcomplete incomplete +imediately immediately +imense immense +imigrant emigrant, immigrant +imigrated emigrated, immigrated +imigration emigration, immigration +iminent eminent, imminent, immanent +immediatley immediately +immediatly immediately +immidately immediately +immidiately immediately +immitate imitate +immitated imitated +immitating imitating +immitator imitator +immunosupressant immunosuppressant +impecabbly impeccably +impedence impedance +implamenting implementing +impliment implement +implimented implemented +imploys employs +importamt important +imprioned imprisoned +imprisonned imprisoned +improvision improvisation +improvments improvements +inablility inability +inaccessable inaccessible +inadiquate inadequate +inadquate inadequate +inadvertant inadvertent +inadvertantly inadvertently +inagurated inaugurated +inaguration inauguration +inappropiate inappropriate +inaugures inaugurates +inbalance imbalance +inbalanced imbalanced +inbetween between +incarcirated incarcerated +incidentially incidentally +incidently incidentally +inclreased increased +includ include +includng including +incompatabilities incompatibilities +incompatability incompatibility +incompatable incompatible +incompatablities incompatibilities +incompatablity incompatibility +incompatiblities incompatibilities +incompatiblity incompatibility +incompetance incompetence +incompetant incompetent +incomptable incompatible +incomptetent incompetent +inconsistant inconsistent +incorperation incorporation +incorportaed incorporated +incorprates incorporates +incorruptable incorruptible +incramentally incrementally +increadible incredible +incredable incredible +inctroduce introduce +inctroduced introduced +incuding including +incunabla incunabula +indefinately indefinitely +indefineable undefinable +indefinitly indefinitely +indentical identical +indepedantly independently +indepedence independence +independance independence +independant independent +independantly independently +independece independence +independendet independent +indictement indictment +indigineous indigenous +indipendence independence +indipendent independent +indipendently independently +indespensible indispensable +indespensable indispensable +indispensible indispensable +indisputible indisputable +indisputibly indisputably +indite indict +individualy individually +indpendent independent +indpendently independently +indulgue indulge +indutrial industrial +indviduals individuals +inefficienty inefficiently +inevatible inevitable +inevitible inevitable +inevititably inevitably +infalability infallibility +infallable infallible +infectuous infectious +infered inferred +infilitrate infiltrate +infilitrated infiltrated +infilitration infiltration +infinit infinite +inflamation inflammation +influencial influential +influented influenced +infomation information +informtion information +infrantryman infantryman +infrigement infringement +ingenius ingenious +ingreediants ingredients +inhabitans inhabitants +inherantly inherently +inheritage heritage, inheritance +inheritence inheritance +inital initial +initally initially +initation initiation +initiaitive initiative +inlcuding including +inmigrant immigrant +inmigrants immigrants +innoculated inoculated +inocence innocence +inofficial unofficial +inot into +inpeach impeach +inpolite impolite +inprisonment imprisonment +inproving improving +insectiverous insectivorous +insensative insensitive +inseperable inseparable +insistance insistence +insitution institution +insitutions institutions +inspite in spite, inspire +instade instead +instatance instance +institue institute +instuction instruction +instuments instruments +instutionalized institutionalized +instutions intuitions +insurence insurance +intelectual intellectual +inteligence intelligence +inteligent intelligent +intenational international +intepretation interpretation +intepretator interpretor +interational international +interbread interbreed, interbred +interchangable interchangeable +interchangably interchangeably +intercontinetal intercontinental +intered interred, interned +interelated interrelated +interferance interference +interfereing interfering +intergrated integrated +intergration integration +interm interim +internation international +interpet interpret +interrim interim +interrugum interregnum +intertaining entertaining +interupt interrupt +intervines intervenes +intevene intervene +intial initial +intially initially +intrduced introduced +intrest interest +introdued introduced +intruduced introduced +intrusted entrusted +intutive intuitive +intutively intuitively +inudstry industry +inumerable enumerable, innumerable +inventer inventor +invertibrates invertebrates +investingate investigate +involvment involvement +irelevent irrelevant +iresistable irresistible +iresistably irresistibly +iresistible irresistible +iresistibly irresistibly +iritable irritable +iritated irritated +ironicly ironically +irregardless regardless +irrelevent irrelevant +irreplacable irreplaceable +irresistable irresistible +irresistably irresistibly +isnt isn't +Israelies Israelis +issueing issuing +itnroduced introduced +iunior junior +iwll will +iwth with +Japanes Japanese +jaques jacques +jeapardy jeopardy +jewllery jewellery +Johanine Johannine +Jospeh Joseph +jouney journey +journied journeyed +journies journeys +jstu just +jsut just +Juadaism Judaism +Juadism Judaism +judical judicial +judisuary judiciary +juducial judicial +juristiction jurisdiction +juristictions jurisdictions +kindergarden kindergarten +klenex kleenex +knifes knives +knive knife +knowlege knowledge +knowlegeable knowledgeable +knwo know +knwos knows +konw know +konws knows +kwno know +labatory lavatory, laboratory +labled labelled, labeled +labratory laboratory +laguage language +laguages languages +larg large +largst largest +larrry larry +lastr last +lattitude latitude +launchs launch +launhed launched +lavae larvae +layed laid +lazyness laziness +leaded led +leage league +leanr lean, learn, leaner +leathal lethal +lefted left +legitamate legitimate +legitmate legitimate +leibnitz leibniz +lenght length +leran learn +lerans learns +lieuenant lieutenant +leutenant lieutenant +levetate levitate +levetated levitated +levetates levitates +levetating levitating +levle level +liasion liaison +liason liaison +liasons liaisons +libary library +libell libel +libguistic linguistic +libguistics linguistics +libitarianisn libertarianism +lible libel, liable +lieing lying +liek like +liekd liked +liesure leisure +lieved lived +liftime lifetime +lightyear light year +lightyears light years +likelyhood likelihood +linnaena linnaean +lippizaner lipizzaner +liquify liquefy +liscense license, licence +lisence license, licence +lisense license, licence +listners listeners +litature literature +literture literature +littel little +litterally literally +liuke like +livley lively +lmits limits +loev love +lonelyness loneliness +longitudonal longitudinal +lonley lonely +lonly lonely, only +loosing losing +lotharingen lothringen +lsat last +lukid likud +lveo love +lvoe love +Lybia Libya +mackeral mackerel +magasine magazine +magincian magician +magnificient magnificent +magolia magnolia +mailny mainly +maintainance maintenance +maintainence maintenance +maintance maintenance +maintenence maintenance +maintinaing maintaining +maintioned mentioned +majoroty majority +maked marked, made +makse makes +Malcom Malcolm +maltesian Maltese +mamal mammal +mamalian mammalian +managable manageable, manageably +managment management +manisfestations manifestations +manoeuverability maneuverability +manouver maneuver, manoeuvre +manouverability maneuverability, manoeuvrability, manoeuverability +manouverable maneuverable, manoeuvrable +manouvers maneuvers, manoeuvres +mantained maintained +manuever maneuver, manoeuvre +manuevers maneuvers, manoeuvres +manufacturedd manufactured +manufature manufacture +manufatured manufactured +manufaturing manufacturing +manuver maneuver +mariage marriage +marjority majority +markes marks +marketting marketing +marmelade marmalade +marrage marriage +marraige marriage +marrtyred martyred +marryied married +Massachussets Massachusetts +Massachussetts Massachusetts +massmedia mass media +masterbation masturbation +mataphysical metaphysical +materalists materialist +mathamatics mathematics +mathematican mathematician +mathematicas mathematics +matheticians mathematicians +mathmatically mathematically +mathmatician mathematician +mathmaticians mathematicians +mccarthyst mccarthyist +mchanics mechanics +meaninng meaning +mear wear, mere, mare +mechandise merchandise +medacine medicine +medeival medieval +medevial medieval +mediciney mediciny +medievel medieval +mediterainnean mediterranean +Mediteranean Mediterranean +meerkrat meerkat +melieux milieux +membranaphone membranophone +memeber member +menally mentally +meranda veranda, Miranda +mercentile mercantile +messanger messenger +messenging messaging +metalic metallic +metalurgic metallurgic +metalurgical metallurgical +metalurgy metallurgy +metamorphysis metamorphosis +metaphoricial metaphorical +meterologist meteorologist +meterology meteorology +methaphor metaphor +methaphors metaphors +Michagan Michigan +micoscopy microscopy +midwifes midwives +mileau milieu +milennia millennia +milennium millennium +mileu milieu +miliary military +milion million +miliraty military +millenia millennia +millenial millennial +millenialism millennialism +millenium millennium +millepede millipede +millioniare millionaire +millitary military +millon million +miltary military +minature miniature +minerial mineral +miniscule minuscule +ministery ministry +minstries ministries +minstry ministry +minumum minimum +mirrorred mirrored +miscelaneous miscellaneous +miscellanious miscellaneous +miscellanous miscellaneous +mischeivous mischievous +mischevious mischievous +mischievious mischievous +misdameanor misdemeanor +misdameanors misdemeanors +misdemenor misdemeanor +misdemenors misdemeanors +misfourtunes misfortunes +misile missile +Misouri Missouri +mispell misspell +mispelled misspelled +mispelling misspelling +missen mizzen +Missisipi Mississippi +Missisippi Mississippi +missle missile +missonary missionary +misterious mysterious +mistery mystery +misteryous mysterious +mkae make +mkaes makes +mkaing making +mkea make +moderm modem +modle model +moent moment +moeny money +mohammedans muslims +moil mohel +moleclues molecules +momento memento +monestaries monasteries +monestary monastery, monetary +monickers monikers +monolite monolithic +Monserrat Montserrat +montains mountains +montanous mountainous +monts months +montypic monotypic +moreso more, more so +morgage mortgage +Morisette Morissette +Morrisette Morissette +morroccan moroccan +morrocco morocco +morroco morocco +mosture moisture +motiviated motivated +mounth month +movei movie +movment movement +mroe more +mucuous mucous +muder murder +mudering murdering +muhammadan muslim +multicultralism multiculturalism +multipled multiplied +multiplers multipliers +munbers numbers +muncipalities municipalities +muncipality municipality +munnicipality municipality +muscels mussels, muscles +muscial musical +muscician musician +muscicians musicians +mutiliated mutilated +myraid myriad +mysef myself +mysogynist misogynist +mysogyny misogyny +mysterous mysterious +Mythraic Mithraic +naieve naive +Napoleonian Napoleonic +naturaly naturally +naturely naturally +naturual natural +naturually naturally +Nazereth Nazareth +neccesarily necessarily +neccesary necessary +neccessarily necessarily +neccessary necessary +neccessities necessities +necesarily necessarily +necesary necessary +necessiate necessitate +neglible negligible +negligable negligible +negociate negotiate +negociation negotiation +negociations negotiations +negotation negotiation +neice niece, nice +neigborhood neighborhood +neigbour neighbour, neighbor +neigbourhood neighbourhood +neigbouring neighbouring, neighboring +neigbours neighbours, neighbors +neolitic neolithic +nessasarily necessarily +nessecary necessary +nestin nesting +neverthless nevertheless +newletters newsletters +Newyorker New Yorker +nickle nickel +nightfa;; nightfall +nightime nighttime +nineth ninth +ninteenth nineteenth +ninties 1990s +ninty ninety +nkow know +nkwo know +nmae name +noncombatents noncombatants +nonsence nonsense +nontheless nonetheless +noone no one +norhern northern +northen northern +northereastern northeastern +notabley notably +noteable notable +noteably notably +noteriety notoriety +noth north +nothern northern +noticable noticeable +noticably noticeably +noticeing noticing +noticible noticeable +notwhithstanding notwithstanding +noveau nouveau +nowdays nowadays +nowe now +nto not +nucular nuclear +nuculear nuclear +nuisanse nuisance +Nullabour Nullarbor +numberous numerous +Nuremburg Nuremberg +nusance nuisance +nutritent nutrient +nutritents nutrients +nuturing nurturing +obediance obedience +obediant obedient +obession obsession +obssessed obsessed +obstacal obstacle +obstancles obstacles +obstruced obstructed +ocasion occasion +ocasional occasional +ocasionally occasionally +ocasionaly occasionally +ocasioned occasioned +ocasions occasions +ocassion occasion +ocassional occasional +ocassionally occasionally +ocassionaly occasionally +ocassioned occasioned +ocassions occasions +occaison occasion +occassion occasion +occassional occasional +occassionally occasionally +occassionaly occasionally +occassioned occasioned +occassions occasions +occationally occasionally +occour occur +occurance occurrence +occurances occurrences +occured occurred +occurence occurrence +occurences occurrences +occuring occurring +occurr occur +occurrance occurrence +occurrances occurrences +octohedra octahedra +octohedral octahedral +octohedron octahedron +ocuntries countries +ocuntry country +ocurr occur +ocurrance occurrence +ocurred occurred +ocurrence occurrence +offcers officers +offcially officially +offereings offerings +offical official +officals officials +offically officially +officaly officially +officialy officially +offred offered +oftenly often +oging going, ogling +omision omission +omited omitted +omiting omitting +omlette omelette +ommision omission +ommited omitted +ommiting omitting +ommitted omitted +ommitting omitting +omniverous omnivorous +omniverously omnivorously +omre more +onot note, not +onyl only +openess openness +oponent opponent +oportunity opportunity +opose oppose +oposite opposite +oposition opposition +oppenly openly +oppinion opinion +opponant opponent +oppononent opponent +oppositition opposition +oppossed opposed +opprotunity opportunity +opression oppression +opressive oppressive +opthalmic ophthalmic +opthalmologist ophthalmologist +opthalmology ophthalmology +opthamologist ophthalmologist +optmizations optimizations +optomism optimism +orded ordered +organim organism +organiztion organization +orgin origin, organ +orginal original +orginally originally +orginize organise +oridinarily ordinarily +origanaly originally +originall original, originally +originaly originally +originially originally +originnally originally +origional original +orignally originally +orignially originally +otehr other +ouevre oeuvre +overshaddowed overshadowed +overthere over there +overwelming overwhelming +overwheliming overwhelming +owrk work +owudl would +oxigen oxygen +oximoron oxymoron +paide paid +paitience patience +palce place, palace +paleolitic paleolithic +paliamentarian parliamentarian +Palistian Palestinian +Palistinian Palestinian +Palistinians Palestinians +pallete palette +pamflet pamphlet +pamplet pamphlet +pantomine pantomime +Papanicalou Papanicolaou +paralel parallel +paralell parallel +paralelly parallelly +paralely parallelly +parallely parallelly +paranthesis parenthesis +paraphenalia paraphernalia +parellels parallels +parituclar particular +parliment parliament +parrakeets parakeets +parralel parallel +parrallel parallel +parrallell parallel +parrallelly parallelly +parrallely parallelly +partialy partially +particually particularly +particualr particular +particuarly particularly +particularily particularly +particulary particularly +pary party +pased passed +pasengers passengers +passerbys passersby +pasttime pastime +pastural pastoral +paticular particular +pattented patented +pavillion pavilion +payed paid +peacefuland peaceful and +peageant pageant +peculure peculiar +pedestrain pedestrian +peice piece +Peloponnes Peloponnesus +penatly penalty +penerator penetrator +penisula peninsula +penisular peninsular +penninsula peninsula +penninsular peninsular +pennisula peninsula +pensinula peninsula +peom poem +peoms poems +peopel people +peotry poetry +perade parade +percepted perceived +percieve perceive +percieved perceived +perenially perennially +perfomers performers +performence performance +performes performed, performs +perhasp perhaps +perheaps perhaps +perhpas perhaps +peripathetic peripatetic +peristent persistent +perjery perjury +perjorative pejorative +permanant permanent +permenant permanent +permenantly permanently +permissable permissible +perogative prerogative +peronal personal +perosnality personality +perphas perhaps +perpindicular perpendicular +perseverence perseverance +persistance persistence +persistant persistent +personel personnel, personal +personell personnel +personnell personnel +persuded persuaded +persue pursue +persued pursued +persuing pursuing +persuit pursuit +persuits pursuits +pertubation perturbation +pertubations perturbations +pessiary pessary +petetion petition +Pharoah Pharaoh +phenomenom phenomenon +phenomenonal phenomenal +phenomenonly phenomenally +phenomonenon phenomenon +phenomonon phenomenon +phenonmena phenomena +Philipines Philippines +philisopher philosopher +philisophical philosophical +philisophy philosophy +Phillipine Philippine +Phillipines Philippines +Phillippines Philippines +phillosophically philosophically +philospher philosopher +philosphies philosophies +philosphy philosophy +Phonecian Phoenecian +phongraph phonograph +phylosophical philosophical +physicaly physically +pich pitch +pilgrimmage pilgrimage +pilgrimmages pilgrimages +pinapple pineapple +pinnaple pineapple +pinoneered pioneered +plagarism plagiarism +planation plantation +planed planned +plantiff plaintiff +plateu plateau +plausable plausible +playright playwright +playwrite playwright +playwrites playwrights +pleasent pleasant +plebicite plebiscite +plesant pleasant +poeoples peoples +poety poetry +poisin poison +polical political +polinator pollinator +polinators pollinators +politican politician +politicans politicians +poltical political +polute pollute +poluted polluted +polutes pollutes +poluting polluting +polution pollution +polyphonyic polyphonic +polysaccaride polysaccharide +polysaccharid polysaccharide +pomegranite pomegranate +pomotion promotion +poportional proportional +popoulation population +popularaty popularity +populare popular +populer popular +portayed portrayed +portraing portraying +Portugese Portuguese +portuguease portuguese +posess possess +posessed possessed +posesses possesses +posessing possessing +posession possession +posessions possessions +posion poison +positon position, positron +possable possible +possably possibly +posseses possesses +possesing possessing +possesion possession +possessess possesses +possibile possible +possibilty possibility +possiblility possibility +possiblilty possibility +possiblities possibilities +possiblity possibility +possition position +Postdam Potsdam +posthomous posthumous +postion position +postive positive +potatos potatoes +portait portrait +potrait portrait +potrayed portrayed +poulations populations +poverful powerful +poweful powerful +powerfull powerful +practial practical +practially practically +practicaly practically +practicioner practitioner +practicioners practitioners +practicly practically +practioner practitioner +practioners practitioners +prairy prairie +prarie prairie +praries prairies +pratice practice +preample preamble +precedessor predecessor +preceed precede +preceeded preceded +preceeding preceding +preceeds precedes +precentage percentage +precice precise +precisly precisely +precurser precursor +predecesors predecessors +predicatble predictable +predicitons predictions +predomiantly predominately +prefered preferred +prefering preferring +preferrably preferably +pregancies pregnancies +preiod period +preliferation proliferation +premeire premiere +premeired premiered +premillenial premillennial +preminence preeminence +premission permission +Premonasterians Premonstratensians +preocupation preoccupation +prepair prepare +prepartion preparation +prepatory preparatory +preperation preparation +preperations preparations +preriod period +presedential presidential +presense presence +presidenital presidential +presidental presidential +presitgious prestigious +prespective perspective +prestigeous prestigious +prestigous prestigious +presumabely presumably +presumibly presumably +pretection protection +prevelant prevalent +preverse perverse +previvous previous +pricipal principal +priciple principle +priestood priesthood +primarly primarily +primative primitive +primatively primitively +primatives primitives +primordal primordial +priveledges privileges +privelege privilege +priveleged privileged +priveleges privileges +privelige privilege +priveliged privileged +priveliges privileges +privelleges privileges +privilage privilege +priviledge privilege +priviledges privileges +privledge privilege +privte private +probabilaty probability +probablistic probabilistic +probablly probably +probalibity probability +probaly probably +probelm problem +proccess process +proccessing processing +procede proceed, precede +proceded proceeded, preceded +procedes proceeds, precedes +procedger procedure +proceding proceeding, preceding +procedings proceedings +proceedure procedure +proces process +processer processor +proclaimation proclamation +proclamed proclaimed +proclaming proclaiming +proclomation proclamation +profesion profusion, profession +profesor professor +professer professor +proffesed professed +proffesion profession +proffesional professional +proffesor professor +profilic prolific +progessed progressed +programable programmable +progrom pogrom, program +progroms pogroms, programs +prohabition prohibition +prologomena prolegomena +prominance prominence +prominant prominent +prominantly prominently +prominately prominently, predominately +promiscous promiscuous +promotted promoted +pronomial pronominal +pronouced pronounced +pronounched pronounced +pronounciation pronunciation +proove prove +prooved proved +prophacy prophecy +propietary proprietary +propmted prompted +propoganda propaganda +propogate propagate +propogates propagates +propogation propagation +propostion proposition +propotions proportions +propper proper +propperly properly +proprietory proprietary +proseletyzing proselytizing +protaganist protagonist +protaganists protagonists +protocal protocol +protoganist protagonist +protrayed portrayed +protruberance protuberance +protruberances protuberances +prouncements pronouncements +provacative provocative +provded provided +provicial provincial +provinicial provincial +provisonal provisional +provisiosn provision +proximty proximity +pseudononymous pseudonymous +pseudonyn pseudonym +psuedo pseudo +psycology psychology +psyhic psychic +publicaly publicly +puchasing purchasing +Pucini Puccini +Puertorrican Puerto Rican +Puertorricans Puerto Ricans +pumkin pumpkin +puritannical puritanical +purposedly purposely +purpotedly purportedly +pursuade persuade +pursuaded persuaded +pursuades persuades +pususading persuading +puting putting +pwoer power +pyscic psychic +qtuie quite, quiet +quantaty quantity +quantitiy quantity +quarantaine quarantine +Queenland Queensland +questonable questionable +quicklyu quickly +quinessential quintessential +quitted quit +quizes quizzes +qutie quite, quiet +rabinnical rabbinical +racaus raucous +radiactive radioactive +radify ratify +raelly really +rarified rarefied +reaccurring recurring +reacing reaching +reacll recall +readmition readmission +realitvely relatively +realsitic realistic +realtions relations +realy really +realyl really +reasearch research +rebiulding rebuilding +rebllions rebellions +rebounce rebound +reccomend recommend +reccomendations recommendations +reccomended recommended +reccomending recommending +reccommend recommend +reccommended recommended +reccommending recommending +reccuring recurring +receeded receded +receeding receding +receivedfrom received from +recepient recipient +recepients recipients +receving receiving +rechargable rechargeable +reched reached +recide reside +recided resided +recident resident +recidents residents +reciding residing +reciepents recipients +reciept receipt +recieve receive +recieved received +reciever receiver +recievers receivers +recieves receives +recieving receiving +recipiant recipient +recipiants recipients +recived received +recivership receivership +recogise recognise +recogize recognize +recomend recommend +recomended recommended +recomending recommending +recomends recommends +recommedations recommendations +reconaissance reconnaissance +reconcilation reconciliation +reconized recognized +reconnaissence reconnaissance +recontructed reconstructed +recordproducer record producer +recquired required +recrational recreational +recrod record +recuiting recruiting +recuring recurring +recurrance recurrence +rediculous ridiculous +reedeming redeeming +reenforced reinforced +refect reflect +refedendum referendum +referal referral +refered referred +referiang referring +refering referring +refernces references +referrence reference +referrs refers +reffered referred +refference reference +refrence reference +refrences references +refrers refers +refridgeration refrigeration +refridgerator refrigerator +refromist reformist +refusla refusal +regardes regards +regluar regular +reguarly regularly +regulaion regulation +regulaotrs regulators +regularily regularly +rehersal rehearsal +reicarnation reincarnation +reigining reigning +reknown renown +reknowned renowned +rela real +relaly really +relatiopnship relationship +relativly relatively +relected reelected +releive relieve +releived relieved +releiver reliever +releses releases +relevence relevance +relevent relevant +reliablity reliability +relient reliant +religeous religious +religous religious +religously religiously +relinqushment relinquishment +relitavely relatively +relized realised, realized +relpacement replacement +remaing remaining +remeber remember +rememberable memorable +rememberance remembrance +remembrence remembrance +remenant remnant +remenicent reminiscent +reminent remnant +reminescent reminiscent +reminscent reminiscent +reminsicent reminiscent +rendevous rendezvous +rendezous rendezvous +renedered rende +renewl renewal +rentors renters +reoccurrence recurrence +reorganision reorganisation +repatition repetition, repartition +repentence repentance +repentent repentant +repeteadly repeatedly +repetion repetition +repid rapid +reponse response +reponsible responsible +reportadly reportedly +represantative representative +representive representative +representives representatives +reproducable reproducible +reprtoire repertoire +repsectively respectively +reptition repetition +requirment requirement +requred required +resaurant restaurant +resembelance resemblance +resembes resembles +resemblence resemblance +resevoir reservoir +resignement resignment +resistable resistible +resistence resistance +resistent resistant +respectivly respectively +responce response +responibilities responsibilities +responisble responsible +responnsibilty responsibility +responsability responsibility +responsibile responsible +responsibilites responsibilities +responsiblity responsibility +ressemblance resemblance +ressemble resemble +ressembled resembled +ressemblence resemblance +ressembling resembling +resssurecting resurrecting +ressurect resurrect +ressurected resurrected +ressurection resurrection +ressurrection resurrection +restaraunt restaurant +restaraunteur restaurateur +restaraunteurs restaurateurs +restaraunts restaurants +restauranteurs restaurateurs +restauration restoration +restauraunt restaurant +resteraunt restaurant +resteraunts restaurants +resticted restricted +restraunt restraint, restaurant +resturant restaurant +resturaunt restaurant +resurecting resurrecting +retalitated retaliated +retalitation retaliation +retreive retrieve +returnd returned +revaluated reevaluated +reveral reversal +reversable reversible +revolutionar revolutionary +rewitten rewritten +rewriet rewrite +rhymme rhyme +rhythem rhythm +rhythim rhythm +rhytmic rhythmic +rigeur rigueur, rigour, rigor +rigourous rigorous +rininging ringing +rised rose +Rockerfeller Rockefeller +rococco rococo +rocord record +roomate roommate +rougly roughly +rucuperate recuperate +rudimentatry rudimentary +rulle rule +runing running +runnung running +russina Russian +Russion Russian +rwite write +rythem rhythm +rythim rhythm +rythm rhythm +rythmic rhythmic +rythyms rhythms +sacrafice sacrifice +sacreligious sacrilegious +sacrifical sacrificial +saftey safety +safty safety +salery salary +sanctionning sanctioning +sandwhich sandwich +Sanhedrim Sanhedrin +santioned sanctioned +sargant sergeant +sargeant sergeant +sasy says, sassy +satelite satellite +satelites satellites +Saterday Saturday +Saterdays Saturdays +satisfactority satisfactorily +satric satiric +satrical satirical +satrically satirically +sattelite satellite +sattelites satellites +saught sought +saveing saving +saxaphone saxophone +scaleable scalable +scandanavia Scandinavia +scaricity scarcity +scavanged scavenged +schedual schedule +scholarhip scholarship +scholarstic scholastic, scholarly +scientfic scientific +scientifc scientific +scientis scientist +scince science +scinece science +scirpt script +scoll scroll +screenwrighter screenwriter +scrutinity scrutiny +scuptures sculptures +seach search +seached searched +seaches searches +secceeded seceded, succeeded +seceed succeed, secede +seceeded succeeded, seceded +secratary secretary +secretery secretary +sedereal sidereal +seeked sought +segementation segmentation +seguoys segues +seige siege +seing seeing +seinor senior +seldomly seldom +senarios scenarios +sence sense +senstive sensitive +sensure censure +seperate separate +seperated separated +seperately separately +seperates separates +seperating separating +seperation separation +seperatism separatism +seperatist separatist +sepina subpoena +sepulchure sepulchre, sepulcher +sepulcre sepulchre, sepulcher +sergent sergeant +settelement settlement +settlment settlement +severeal several +severley severely +severly severely +sevice service +shaddow shadow +shamen shaman, shamans +sheat sheath, sheet, cheat +sheild shield +sherif sheriff +shineing shining +shiped shipped +shiping shipping +shopkeeepers shopkeepers +shorly shortly +shortwhile short while +shoudl should +shoudln should, shouldn't +shouldnt shouldn't +shreak shriek +shrinked shrunk +sicne since +sideral sidereal +sieze seize, size +siezed seized, sized +siezing seizing, sizing +siezure seizure +siezures seizures +siginificant significant +signficant significant +signficiant significant +signfies signifies +signifantly significantly +significently significantly +signifigant significant +signifigantly significantly +signitories signatories +signitory signatory +similarily similarly +similiar similar +similiarity similarity +similiarly similarly +simmilar similar +simpley simply +simplier simpler +simultanous simultaneous +simultanously simultaneously +sincerley sincerely +singsog singsong +sinse sines, since +Sionist Zionist +Sionists Zionists +Sixtin Sistine +Skagerak Skagerrak +skateing skating +slaugterhouses slaughterhouses +slowy slowly +smae same +smealting smelting +smoe some +sneeks sneaks +snese sneeze +socalism socialism +socities societies +soem some +sofware software +sohw show +soilders soldiers +solatary solitary +soley solely +soliders soldiers +soliliquy soliloquy +soluable soluble +somene someone +somtimes sometimes +somwhere somewhere +sophicated sophisticated +sorceror sorcerer +sorrounding surrounding +sotry story +sotyr satyr, story +soudn sound +soudns sounds +sould could, should, sold +sountrack soundtrack +sourth south +sourthern southern +souvenier souvenir +souveniers souvenirs +soveits soviets +sovereignity sovereignty +soverign sovereign +soverignity sovereignty +soverignty sovereignty +spainish Spanish +speach speech +specfic specific +speciallized specialised, specialized +specif specific, specify +specifiying specifying +speciman specimen +spectauclar spectacular +spectaulars spectaculars +spects aspects, expects +spectum spectrum +speices species +spendour splendour +spermatozoan spermatozoon +spoace space +sponser sponsor +sponsered sponsored +spontanous spontaneous +sponzored sponsored +spoonfulls spoonfuls +sppeches speeches +spreaded spread +sprech speech +spred spread +spriritual spiritual +spritual spiritual +sqaure square +stablility stability +stainlees stainless +staion station +standars standards +stange strange +startegic strategic +startegies strategies +startegy strategy +stateman statesman +statememts statements +statment statement +steriods steroids +sterotypes stereotypes +stilus stylus +stingent stringent +stiring stirring +stirrs stirs +stlye style +stong strong +stopry story +storeis stories +storise stories +stornegst strongest +stoyr story +stpo stop +stradegies strategies +stradegy strategy +strat start, strata +stratagically strategically +streemlining streamlining +stregth strength +strenghen strengthen +strenghened strengthened +strenghening strengthening +strenght strength +strenghten strengthen +strenghtened strengthened +strenghtening strengthening +strengtened strengthened +strenous strenuous +strictist strictest +strikely strikingly +strnad strand +stroy story, destroy +structual structural +stubborness stubbornness +stucture structure +stuctured structured +studdy study +studing studying +stuggling struggling +sturcture structure +subcatagories subcategories +subcatagory subcategory +subconsiously subconsciously +subjudgation subjugation +submachne submachine +subpecies subspecies +subsidary subsidiary +subsiduary subsidiary +subsquent subsequent +subsquently subsequently +substace substance +substancial substantial +substatial substantial +substituded substituted +substract subtract +substracted subtracted +substracting subtracting +substraction subtraction +substracts subtracts +subtances substances +subterranian subterranean +suburburban suburban +succceeded succeeded +succcesses successes +succedded succeeded +succeded succeeded +succeds succeeds +succesful successful +succesfully successfully +succesfuly successfully +succesion succession +succesive successive +successfull successful +successully successfully +succsess success +succsessfull successful +suceed succeed +suceeded succeeded +suceeding succeeding +suceeds succeeds +sucesful successful +sucesfully successfully +sucesfuly successfully +sucesion succession +sucess success +sucesses successes +sucessful successful +sucessfull successful +sucessfully successfully +sucessfuly successfully +sucession succession +sucessive successive +sucessor successor +sucessot successor +sucide suicide +sucidial suicidal +sufferage suffrage +sufferred suffered +sufferring suffering +sufficent sufficient +sufficently sufficiently +sumary summary +sunglases sunglasses +suop soup +superceeded superseded +superintendant superintendent +suphisticated sophisticated +suplimented supplemented +supose suppose +suposed supposed +suposedly supposedly +suposes supposes +suposing supposing +supplamented supplemented +suppliementing supplementing +suppoed supposed +supposingly supposedly +suppy supply +supress suppress +supressed suppressed +supresses suppresses +supressing suppressing +suprise surprise +suprised surprised +suprising surprising +suprisingly surprisingly +suprize surprise +suprized surprised +suprizing surprising +suprizingly surprisingly +surfce surface +surley surly, surely +suround surround +surounded surrounded +surounding surrounding +suroundings surroundings +surounds surrounds +surplanted supplanted +surpress suppress +surpressed suppressed +surprize surprise +surprized surprised +surprizing surprising +surprizingly surprisingly +surrended surrounded, surrendered +surrepetitious surreptitious +surrepetitiously surreptitiously +surreptious surreptitious +surreptiously surreptitiously +surronded surrounded +surrouded surrounded +surrouding surrounding +surrundering surrendering +surveilence surveillance +surveill surveil +surveyer surveyor +surviver survivor +survivers survivors +survivied survived +suseptable susceptible +suseptible susceptible +suspention suspension +swaer swear +swaers swears +swepth swept +swiming swimming +syas says +symetrical symmetrical +symetrically symmetrically +symetry symmetry +symettric symmetric +symmetral symmetric +symmetricaly symmetrically +synagouge synagogue +syncronization synchronization +synonomous synonymous +synonymns synonyms +synphony symphony +syphyllis syphilis +sypmtoms symptoms +syrap syrup +sysmatically systematically +sytem system +sytle style +tabacco tobacco +tahn than +taht that +talekd talked +targetted targeted +targetting targeting +tast taste +tath that +tattooes tattoos +taxanomic taxonomic +taxanomy taxonomy +teached taught +techician technician +techicians technicians +techiniques techniques +technitian technician +technnology technology +technolgy technology +teh the +tehy they +telelevision television +televsion television +telphony telephony +temerature temperature +temparate temperate +temperarily temporarily +temperment temperament +tempertaure temperature +temperture temperature +temprary temporary +tenacle tentacle +tenacles tentacles +tendacy tendency +tendancies tendencies +tendancy tendency +tennisplayer tennis player +tepmorarily temporarily +terrestial terrestrial +terriories territories +terriory territory +territorist terrorist +territoy territory +terroist terrorist +testiclular testicular +tghe the +thast that, that's +theather theater, theatre +theese these +theif thief +theives thieves +themselfs themselves +themslves themselves +ther there, their, the +therafter thereafter +therby thereby +theri their +thgat that +thge the +thier their +thign thing +thigns things +thigsn things +thikn think +thikning thinking, thickening +thikns thinks +thiunk think +thn then +thna than +thne then +thnig thing +thnigs things +thoughout throughout +threatend threatened +threatning threatening +threee three +threshhold threshold +thrid third +throrough thorough +throughly thoroughly +throught thought, through, throughout +througout throughout +thru through +thsi this +thsoe those +thta that +thyat that +tiem time, Tim +tihkn think +tihs this +timne time +tiome time, tome +tje the +tjhe the +tjpanishad upanishad +tkae take +tkaes takes +tkaing taking +tlaking talking +tobbaco tobacco +todays today's +todya today +toghether together +tolerence tolerance +Tolkein Tolkien +tomatos tomatoes +tommorow tomorrow +tommorrow tomorrow +tongiht tonight +toriodal toroidal +tormenters tormentors +torpeados torpedoes +torpedos torpedoes +tothe to the +toubles troubles +tounge tongue +tourch torch, touch +towords towards +towrad toward +tradionally traditionally +traditionaly traditionally +traditionnal traditional +traditition tradition +tradtionally traditionally +trafficed trafficked +trafficing trafficking +trafic traffic +trancendent transcendent +trancending transcending +tranform transform +tranformed transformed +transcendance transcendence +transcendant transcendent +transcendentational transcendental +transcripting transcribing, transcription +transending transcending +transesxuals transsexuals +transfered transferred +transfering transferring +transformaton transformation +transistion transition +translater translator +translaters translators +transmissable transmissible +transporation transportation +tremelo tremolo +tremelos tremolos +triguered triggered +triology trilogy +troling trolling +troup troupe +troups troupes, troops +truely truly +trustworthyness trustworthiness +turnk turnkey, trunk +Tuscon Tucson +tust trust +twelth twelfth +twon town +twpo two +tyhat that +tyhe they +typcial typical +typicaly typically +tyranies tyrannies +tyrany tyranny +tyrranies tyrannies +tyrrany tyranny +ubiquitious ubiquitous +uise use +Ukranian Ukrainian +ultimely ultimately +unacompanied unaccompanied +unahppy unhappy +unanymous unanimous +unathorised unauthorised +unavailible unavailable +unballance unbalance +unbeleivable unbelievable +uncertainity uncertainty +unchallengable unchallengeable +unchangable unchangeable +uncompetive uncompetitive +unconcious unconscious +unconciousness unconsciousness +unconfortability discomfort +uncontitutional unconstitutional +unconvential unconventional +undecideable undecidable +understoon understood +undesireable undesirable +undetecable undetectable +undoubtely undoubtedly +undreground underground +uneccesary unnecessary +unecessary unnecessary +unequalities inequalities +unforetunately unfortunately +unforgetable unforgettable +unforgiveable unforgivable +unfortunatley unfortunately +unfortunatly unfortunately +unfourtunately unfortunately +unihabited uninhabited +unilateraly unilaterally +unilatreal unilateral +unilatreally unilaterally +uninterruped uninterrupted +uninterupted uninterrupted +UnitesStates UnitedStates +univeral universal +univeristies universities +univeristy university +universtiy university +univesities universities +univesity university +unkown unknown +unlikey unlikely +unmanouverable unmaneuverable, unmanoeuvrable +unmistakeably unmistakably +unneccesarily unnecessarily +unneccesary unnecessary +unneccessarily unnecessarily +unneccessary unnecessary +unnecesarily unnecessarily +unnecesary unnecessary +unoffical unofficial +unoperational nonoperational +unoticeable unnoticeable +unplease displease +unplesant unpleasant +unprecendented unprecedented +unprecidented unprecedented +unrepentent unrepentant +unrepetant unrepentant +unrepetent unrepentant +unsed used, unused, unsaid +unsubstanciated unsubstantiated +unsuccesful unsuccessful +unsuccesfully unsuccessfully +unsuccessfull unsuccessful +unsucesful unsuccessful +unsucesfuly unsuccessfully +unsucessful unsuccessful +unsucessfull unsuccessful +unsucessfully unsuccessfully +unsuprised unsurprised +unsuprising unsurprising +unsuprisingly unsurprisingly +unsuprized unsurprised +unsuprizing unsurprising +unsuprizingly unsurprisingly +unsurprized unsurprised +unsurprizing unsurprising +unsurprizingly unsurprisingly +untill until +untranslateable untranslatable +unuseable unusable +unusuable unusable +unviersity university +unwarrented unwarranted +unweildly unwieldy +unwieldly unwieldy +upcomming upcoming +upgradded upgraded +usally usually +useage usage +usefull useful +usefuly usefully +useing using +usualy usually +ususally usually +vaccum vacuum +vaccume vacuum +vacinity vicinity +vaguaries vagaries +vaieties varieties +vailidty validity +valetta valletta +valuble valuable +valueable valuable +varations variations +varient variant +variey variety +varing varying +varities varieties +varity variety +vasall vassal +vasalls vassals +vegatarian vegetarian +vegitable vegetable +vegitables vegetables +vegtable vegetable +vehicule vehicle +vell well +venemous venomous +vengance vengeance +vengence vengeance +verfication verification +verison version +verisons versions +vermillion vermilion +versitilaty versatility +versitlity versatility +vetween between +veyr very +vigeur vigueur, vigour, vigor +vigilence vigilance +vigourous vigorous +villian villain +villification vilification +villify vilify +villin villi, villain, villein +vincinity vicinity +violentce violence +virutal virtual +virtualy virtually +virutally virtually +visable visible +visably visibly +visting visiting +vistors visitors +vitories victories +volcanoe volcano +voleyball volleyball +volontary voluntary +volonteer volunteer +volonteered volunteered +volonteering volunteering +volonteers volunteers +volounteer volunteer +volounteered volunteered +volounteering volunteering +volounteers volunteers +vreity variety +vrey very +vriety variety +vulnerablility vulnerability +vyer very +vyre very +waht what +wanna want to +warantee warranty +wardobe wardrobe +warrent warrant +warrriors warriors +wasnt wasn't +wass was +watn want +wayword wayward +weaponary weaponry +weas was +wehn when +weild wield, wild +weilded wielded +wendsay Wednesday +wensday Wednesday +wereabouts whereabouts +whant want +whants wants +whcih which +wheras whereas +wherease whereas +whereever wherever +whic which +whihc which +whith with +whlch which +whn when +wholey wholly +wholy wholly, holy +whta what +whther whether +wich which, witch +widesread widespread +wief wife +wierd weird +wiew view +wih with +wiht with +wille will +willingless willingness +wirting writing +withdrawl withdrawal, withdraw +witheld withheld +withing within +withold withhold +witht with +witn with +wiull will +wnat want +wnated wanted +wnats wants +wohle whole +wokr work +wokring working +wonderfull wonderful +workststion workstation +worls world +wordlwide worldwide +worshipper worshiper +worshipping worshiping +worstened worsened +woudl would +wresters wrestlers +wriet write +writen written +wroet wrote +wrok work +wroking working +ws was +wtih with +wupport support +xenophoby xenophobia +yaching yachting +yatch yacht +yeasr years +yeild yield +yeilding yielding +Yementite Yemenite, Yemeni +yearm year +yera year +yeras years +yersa years +youseff yousef +youself yourself +ytou you +yuo you +joo you +zeebra zebra + +[[Category:Wikipedia tools]] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am new file mode 100644 index 000000000..b8be6c5b6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.am @@ -0,0 +1,6 @@ +EXTRA_DIST= \ +List_of_common_misspellings.txt \ +Makefile.orig \ +prepare \ +README \ +test diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in new file mode 100644 index 000000000..11d332705 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/Makefile.in @@ -0,0 +1,435 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = tests/suggestiontest +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \ + $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSESLIB = @CURSESLIB@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENCAT = @GENCAT@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC2 = @GLIBC2@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_VISIBILITY = @HAVE_VISIBILITY@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HUNSPELL_VERSION_MAJOR = @HUNSPELL_VERSION_MAJOR@ +HUNSPELL_VERSION_MINOR = @HUNSPELL_VERSION_MINOR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBC = @LTLIBC@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +WOE32 = @WOE32@ +WOE32DLL = @WOE32DLL@ +XFAILED = @XFAILED@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ +List_of_common_misspellings.txt \ +Makefile.orig \ +prepare \ +README \ +test + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/suggestiontest/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/suggestiontest/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README new file mode 100644 index 000000000..c50e05cea --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/README @@ -0,0 +1,16 @@ +source of text data: Wikipedia +http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +For testing Hunspell you need the extended en_US dictionary with phonetic table: +http://hunspell.sourceforge.net/en_US.zip + +test: +make -f Makefile.orig + +test only with Hunspell: + +make -f Makefile.orig single + +test with different input file and dictionaries: + +INPUT=dutchlist.txt HUNSPELL=nl_NL ASPELL=nl make -f Makefile.orig diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare new file mode 100644 index 000000000..a72d931b8 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/prepare @@ -0,0 +1,40 @@ +#!/bin/bash +# Check common misspellings +# input file format: +# word->word1, ... +# Source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +hunspell=../../src/tools/hunspell +hlang=${HUNSPELL:-en_US} +alang=${ASPELL:-en_US} +input=${INPUT:-List_of_common_misspellings.txt} + +# remove bad words recognised by Hunspell as good +cat $input | sed 's/[-]>/ /' | $hunspell -d $hlang -1 -L | + +# remove items with dash for Aspell +grep '^[^-]* ' | + +# remove spaces from end of lines +sed 's/ *$//' >$input.1 + +# remove bad words recognised by Aspell as good +cut -f 1 -d ' ' $input.1 | aspell -l $alang --list | +awk 'FILENAME=="-"{a[$1]=1;next}a[$1]{print$0}' - $input.1 | + +# change commas with tabs +sed 's/, */ /g' >$input.2 + +# remove lines with unrecognised suggestions (except suggestion with spaces) +cut -d ' ' -f 2- $input.2 | tr "\t" "\n" | grep -v ' ' >x.1 +cat x.1 | $hunspell -l -d $hlang >x.2 +cat x.1 | aspell -l $alang --list >>x.2 +cat x.2 | awk 'BEGIN{FS="\t"} +FILENAME=="-"{a[$1]=1;next}a[$2]!=1 && a[$3]!=1{print $0}' - $input.2 >$input.3 + +cut -f 1 -d ' ' $input.3 | aspell -l $alang -a | grep -v ^$ | sed -n '2,$p' | +sed 's/^.*: //;s/, / /g' >$input.4 + +cat $input.3 | $hunspell -d $hlang -a -1 | grep -v ^$ | sed -n '2,$p' | +sed 's/^.*: //;s/, / /g' >$input.5 + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test new file mode 100644 index 000000000..8e6c1cc1f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/suggestiontest/test @@ -0,0 +1,25 @@ +#!/bin/bash +# Check common misspellings +# input file format: +# word->word1, ... +# Source: http://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines + +input=${INPUT:-List_of_common_misspellings.txt} + +function check() { +cat $1 | awk 'BEGIN{maxord=0;FS="\t"}FILENAME=="-"{for (i=1; i<=NF; i++){a[NR,$(i)]=i};max=NR;next}{x1=a[NR-max,$2];x2=a[NR-max,$3];sug++;if($3)sug++;if (!x1&&!x2){mis2++;misrow=misrow"\n"$0};if(!x1||($3 && !x2))mis++;ord+=x1+x2;}END{ +print "Missed rows", misrow; +print "=======================================" +print maxord, "max. suggestion for a word"; +print max, "input rows"; +print mis2, "missing rows"; +print sug, "expected suggestions"; +print mis, "missing suggestions"; +print ord/(sug-mis), "average ranking"; +}' - $2 +} + +test -f $input.4 && check $input.4 $input.3 >result.aspell +check $input.5 $input.3 >result.hunspell +test -f result.aspell && tail -6 result.aspell +tail -6 result.hunspell diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff new file mode 100644 index 000000000..60294d24c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.aff @@ -0,0 +1,15 @@ +# new suggestion methods of Hunspell 1.5: +# capitalization: nasa -> NASA +# long swap: permenant -> permanent +# long mov: Ghandi -> Gandhi +# double two characters: vacacation -> vacation +# space with REP: "alot" -> "a lot" ("a lot" need to be in the dic file.) + +SET UTF-8 +# switch off ngram suggestion for testing +MAXNGRAMSUGS 0 +REP 1 +REP alot a_lot +KEY qwertzuiop|asdfghjkl|yxcvbnm|aq +WORDCHARS . +FORBIDDENWORD ? diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic new file mode 100644 index 000000000..cf7c9aadb --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.dic @@ -0,0 +1,11 @@ +10 +NASA +Gandhi +grateful +permanent +vacation +a +lot +have +which +McDonald diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug new file mode 100644 index 000000000..e277bdb77 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.sug @@ -0,0 +1,12 @@ +NASA +Gandhi +grateful +permanent +vacation +a lot, lot +permanent. Vacation +have +which +Gandhi +McDonald +permanent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong new file mode 100644 index 000000000..4d184d5a6 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/sugutf.wrong @@ -0,0 +1,12 @@ +nasa +Ghandi +greatful +permenant +vacacation +alot +permanent.Vacation +ahev +hwihc +GAndhi +Mcdonald +permqnent diff --git a/extensions/spellcheck/hunspell/tests/unit/data/test.sh b/extensions/spellcheck/hunspell/tests/unit/data/test.sh new file mode 100644 index 000000000..c89ca9bf7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/test.sh @@ -0,0 +1,111 @@ +#!/bin/bash +export LC_ALL="C" + +function check_valgrind_log () { +if [ "$VALGRIND" != "" ]; then + if [ -f $TEMPDIR/test.pid* ]; then + log=`ls $TEMPDIR/test.pid*` + if ! grep -q 'ERROR SUMMARY: 0 error' $log; then + echo "Fail in $NAME $1 checking detected by Valgrind" + echo "$log Valgrind log file moved to $TEMPDIR/badlogs" + mv $log $TEMPDIR/badlogs + exit 1 + fi + if grep -q 'LEAK SUMMARY' $log; then + echo "Memory leak in $NAME $1 checking detected by Valgrind" + echo "$log Valgrind log file moved to $TEMPDIR/badlogs" + mv $log $TEMPDIR/badlogs + exit 1 + fi + rm -f $log + fi +fi +} + +TESTDIR=. +TEMPDIR=$TESTDIR/testSubDir +NAME="$1" +shift + +if [ ! -d $TEMPDIR ]; then + mkdir $TEMPDIR +fi + +shopt -s expand_aliases + +alias hunspell='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la ../src/tools/hunspell' +alias analyze='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la ../src/tools/analyze' + +if [ "$VALGRIND" != "" ]; then + rm -f $TEMPDIR/test.pid* + if [ ! -d $TEMPDIR/badlogs ]; then + mkdir $TEMPDIR/badlogs + fi + + alias hunspell='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la valgrind --tool=$VALGRIND --leak-check=yes --show-reachable=yes --log-file=$TEMPDIR/test.pid ../src/tools/hunspell' + alias analyze='../libtool --mode=execute -dlopen ../src/hunspell/.libs/libhunspell*.la valgrind --tool=$VALGRIND --leak-check=yes --show-reachable=yes --log-file=$TEMPDIR/test.pid ../src/tools/analyze' +fi + +# Tests good words +if test -f $TESTDIR/$NAME.good; then + hunspell -l $* -d $TESTDIR/$NAME <$TESTDIR/$NAME.good >$TEMPDIR/$NAME.good + if test -s $TEMPDIR/$NAME.good; then + echo "=============================================" + echo "Fail in $NAME.good. Good words recognised as wrong:" + cat $TEMPDIR/$NAME.good + rm -f $TEMPDIR/$NAME.good + exit 1 + fi + rm -f $TEMPDIR/$NAME.good +fi + +check_valgrind_log "good words" + +# Tests bad words +if test -f $TESTDIR/$NAME.wrong; then + hunspell -l $* -d $TESTDIR/$NAME <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong + tr -d ' ' <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong.detab + if ! cmp $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.wrong. Bad words recognised as good:" + tr -d ' ' <$TESTDIR/$NAME.wrong >$TEMPDIR/$NAME.wrong.detab + diff $TEMPDIR/$NAME.wrong.detab $TEMPDIR/$NAME.wrong | grep '^<' | sed 's/^..//' + rm -f $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab + exit 1 + fi + rm -f $TEMPDIR/$NAME.wrong $TEMPDIR/$NAME.wrong.detab +fi + +check_valgrind_log "bad words" + +# Tests morphological analysis +if test -f $TESTDIR/$NAME.morph; then + sed 's/ $//' $TESTDIR/$NAME.good >$TEMPDIR/$NAME.good + analyze $TESTDIR/$NAME.aff $TESTDIR/$NAME.dic $TEMPDIR/$NAME.good >$TEMPDIR/$NAME.morph + if ! cmp $TEMPDIR/$NAME.morph $TESTDIR/$NAME.morph >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.morph. Bad analysis?" + diff $TESTDIR/$NAME.morph $TEMPDIR/$NAME.morph | grep '^<' | sed 's/^..//' + rm -f $TEMPDIR/$NAME.morph + exit 1 + fi + rm -f $TEMPDIR/$NAME.{morph,good} +fi + +check_valgrind_log "morphological analysis" + +# Tests suggestions +if test -f $TESTDIR/$NAME.sug; then + hunspell $* -a -d $TESTDIR/$NAME <$TESTDIR/$NAME.wrong | grep '^&' | \ + sed 's/^[^:]*: //' >$TEMPDIR/$NAME.sug + if ! cmp $TEMPDIR/$NAME.sug $TESTDIR/$NAME.sug >/dev/null; then + echo "=============================================" + echo "Fail in $NAME.sug. Bad suggestion?" + diff $TESTDIR/$NAME.sug $TEMPDIR/$NAME.sug + rm -f $TEMPDIR/$NAME.sug + exit 1 + fi + rm -f $TEMPDIR/$NAME.sug +fi + +check_valgrind_log "suggestion" diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff new file mode 100644 index 000000000..f56998b9f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.aff @@ -0,0 +1,3 @@ +SET UTF-8 + +# removing byte order mark from affix file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic new file mode 100644 index 000000000..8b10768e5 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.dic @@ -0,0 +1,2 @@ +1 +apéritif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good new file mode 100644 index 000000000..c344eaf5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.good @@ -0,0 +1,2 @@ +apéritif +APÉRITIF diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff new file mode 100644 index 000000000..784935c84 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.aff @@ -0,0 +1,3 @@ +SET UTF-8 + +# removing byte order mark from dic file diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic new file mode 100644 index 000000000..b763179a0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.dic @@ -0,0 +1,2 @@ +1 +apéritif diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good new file mode 100644 index 000000000..c344eaf5a --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.good @@ -0,0 +1,2 @@ +apéritif +APÉRITIF diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-bom2.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff new file mode 100644 index 000000000..979e3c228 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.aff @@ -0,0 +1 @@ +SET UTF-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic new file mode 100644 index 000000000..4a040eeb0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.dic @@ -0,0 +1,5 @@ +4 # Old Persian numbers (1-4), source: Wikipedia +𐏑 +𐏒 +𐏒𐏑 +𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good new file mode 100644 index 000000000..9f989d339 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.good @@ -0,0 +1,5 @@ +𐏑 +𐏒 +𐏒𐏑 +𐏒𐏒 + diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug new file mode 100644 index 000000000..bfe2a539f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.sug @@ -0,0 +1,2 @@ +𐏒𐏑, 𐏒𐏒 +𐏒𐏑, 𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test new file mode 100644 index 000000000..1d25699aa --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 -1 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong new file mode 100644 index 000000000..d18dfa4c2 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8-nonbmp.wrong @@ -0,0 +1,2 @@ +𐏑𐏒𐏒 +𐏑𐏒𐏒 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff b/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff new file mode 100644 index 000000000..e8934d71b --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.aff @@ -0,0 +1,10 @@ +SET UTF-8 + +SFX A Y 7 +SFX A 0 őő . +SFX A 0 ő o +SFX A 0 ő ó +SFX A ó ő ó +SFX A ó őoo ó +SFX A o őo o +SFX A 0 ó [abcdó] diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic b/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic new file mode 100644 index 000000000..e7cb34daf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.dic @@ -0,0 +1,3 @@ +2 +foo/A +foó/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.good b/extensions/spellcheck/hunspell/tests/unit/data/utf8.good new file mode 100644 index 000000000..08aa4dadf --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.good @@ -0,0 +1,9 @@ +foo +foó +fooőő +fooő +foóő +foő +foőo +foőoo +foóó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utf8.test b/extensions/spellcheck/hunspell/tests/unit/data/utf8.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utf8.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff new file mode 100644 index 000000000..43506afa3 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.aff @@ -0,0 +1,3 @@ +SET UTF-8 +COMPOUNDMIN 3 +COMPOUNDFLAG A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic new file mode 100644 index 000000000..ab90a1b70 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.dic @@ -0,0 +1,9 @@ +8 +foo/A +bar/A +fóó/A +áár/A +xy/A +yz/A +éé/A +őő/A diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good new file mode 100644 index 000000000..1a1a1b19c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.good @@ -0,0 +1,5 @@ +foobar +barfoo +foobarfoo +fóóáár +áárfóó diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test new file mode 100644 index 000000000..cde7c5410 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME -i utf-8 diff --git a/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong new file mode 100644 index 000000000..fa385c1b0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/utfcompound.wrong @@ -0,0 +1,7 @@ +xyyz +fooxy +xyfoo +fooxybar +ééőő +fóóéé +őőáár diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.aff b/extensions/spellcheck/hunspell/tests/unit/data/warn.aff new file mode 100644 index 000000000..d586fa33e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.aff @@ -0,0 +1,13 @@ +# WARN flag +# The signed word, and its suffixed forms result warning message in command-line + +#Use to forbid the words with flag WARN +#FORBIDWARN + +WARN W + +SFX A Y 1 +SFX A 0 s . + +REP 1 +REP foo bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.dic b/extensions/spellcheck/hunspell/tests/unit/data/warn.dic new file mode 100644 index 000000000..d63f6047e --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.dic @@ -0,0 +1,3 @@ +1 +foo/WA +bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.good b/extensions/spellcheck/hunspell/tests/unit/data/warn.good new file mode 100644 index 000000000..542f439a4 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.good @@ -0,0 +1,2 @@ +foo +foos diff --git a/extensions/spellcheck/hunspell/tests/unit/data/warn.test b/extensions/spellcheck/hunspell/tests/unit/data/warn.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/warn.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff new file mode 100644 index 000000000..fdb047b0c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.aff @@ -0,0 +1,12 @@ +PSEUDOROOT X +COMPOUNDFLAG Y + +SFX A Y 1 +SFX A 0 0 . > + +SFX B Y 1 +SFX B 0 0 . <ZERO>> + +SFX C Y 2 +SFX C 0 0/XAB . <ZERODERIV> +SFX C 0 baz/XAB . <DERIV> diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic new file mode 100644 index 000000000..72cba8d34 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.dic @@ -0,0 +1,3 @@ +2 +foo/XA <FOO +bar/XABC <BAR diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.good b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.good new file mode 100644 index 000000000..b1fb3ba5c --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.good @@ -0,0 +1,3 @@ +bar +foo +barbaz diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.morph b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.morph new file mode 100644 index 000000000..bcb788ad7 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.morph @@ -0,0 +1,13 @@ +> bar +analyze(bar) = st:bar <BAR <ZERO>> +analyze(bar) = st:bar <BAR > +analyze(bar) = st:bar <BAR <ZERODERIV> <ZERO>> +analyze(bar) = st:bar <BAR <ZERODERIV> > +stem(bar) = bar +> foo +analyze(foo) = st:foo <FOO > +stem(foo) = foo +> barbaz +analyze(barbaz) = st:bar <BAR <DERIV> <ZERO>> +analyze(barbaz) = st:bar <BAR <DERIV> > +stem(barbaz) = bar diff --git a/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test new file mode 100644 index 000000000..7f4436906 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/data/zeroaffix.test @@ -0,0 +1,4 @@ +#!/bin/sh +DIR="`dirname $0`" +NAME="`basename $0 .test`" +$DIR/test.sh $NAME diff --git a/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js new file mode 100644 index 000000000..a67eeaec0 --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js @@ -0,0 +1,220 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var Cc = Components.classes; +var Ci = Components.interfaces; + +const tests = [ + ["affixes", "iso-8859-1"], + ["condition", "iso-8859-1"], + ["condition-utf", "UTF-8"], + ["base", "iso-8859-1"], + ["base-utf", "UTF-8"], + ["allcaps", "iso-8859-1"], + ["allcaps-utf", "UTF-8"], + ["allcaps2", "iso-8859-1"], + ["allcaps3", "iso-8859-1"], + ["keepcase", "iso-8859-1"], + ["i58202", "iso-8859-1"], + ["map", "iso-8859-1"], + ["rep", "iso-8859-1"], + ["sug", "iso-8859-1"], + ["sugutf", "UTF-8"], + ["phone", "iso-8859-1"], + ["flag", "iso-8859-1"], + ["flaglong", "iso-8859-1"], + ["flagnum", "iso-8859-1"], + ["flagutf8", "UTF-8"], + ["slash", "iso-8859-1"], + ["forbiddenword", "iso-8859-1"], + ["nosuggest", "iso-8859-1"], + ["alias", "iso-8859-1"], + ["alias2", "iso-8859-1"], + ["alias3", "iso-8859-1"], + ["breakdefault", "iso-8859-1"], + ["break", "UTF-8"], + ["needaffix", "iso-8859-1"], + ["needaffix2", "iso-8859-1"], + ["needaffix3", "iso-8859-1"], + ["needaffix4", "iso-8859-1"], + ["needaffix5", "iso-8859-1"], + ["circumfix", "iso-8859-1"], + ["fogemorpheme", "iso-8859-1"], + ["onlyincompound", "iso-8859-1"], + ["complexprefixes", "iso-8859-1"], + ["complexprefixes2", "iso-8859-1"], + ["complexprefixesutf", "UTF-8"], + ["conditionalprefix", "iso-8859-1"], + ["zeroaffix", "iso-8859-1"], + ["utf8", "UTF-8"], + ["utf8-bom", "UTF-8", {1: "todo"}], + ["utf8-bom2", "UTF-8", {1: "todo"}], + ["utf8-nonbmp", "UTF-8", {1: "todo", 2: "todo", 3: "todo", 4: "todo"}], + ["compoundflag", "iso-8859-1"], + ["compoundrule", "iso-8859-1"], + ["compoundrule2", "iso-8859-1"], + ["compoundrule3", "iso-8859-1"], + ["compoundrule4", "iso-8859-1"], + ["compoundrule5", "UTF-8"], + ["compoundrule6", "iso-8859-1"], + ["compoundrule7", "iso-8859-1"], + ["compoundrule8", "iso-8859-1"], + ["compoundaffix", "iso-8859-1"], + ["compoundaffix2", "iso-8859-1"], + ["compoundaffix3", "iso-8859-1"], + ["checkcompounddup", "iso-8859-1"], + ["checkcompoundtriple", "iso-8859-1"], + ["simplifiedtriple", "iso-8859-1"], + ["checkcompoundrep", "iso-8859-1"], + ["checkcompoundcase2", "iso-8859-1"], + ["checkcompoundcaseutf", "UTF-8"], + ["checkcompoundpattern", "iso-8859-1"], + ["checkcompoundpattern2", "iso-8859-1"], + ["checkcompoundpattern3", "iso-8859-1"], + ["checkcompoundpattern4", "iso-8859-1"], + ["utfcompound", "UTF-8"], + ["checksharps", "iso-8859-1"], + ["checksharpsutf", "UTF-8"], + ["germancompounding", "iso-8859-1"], + ["germancompoundingold", "iso-8859-1"], + ["i35725", "iso-8859-1"], + ["i53643", "iso-8859-1"], + ["i54633", "iso-8859-1"], + ["i54980", "iso-8859-1", {1: "todo", 3: "todo"}], + ["maputf", "UTF-8"], + ["reputf", "UTF-8"], + ["ignore", "iso-8859-1"], + ["ignoreutf", "UTF-8", + {1: "todo", 2: "todo", 3: "todo", 4: "todo", 5: "todo", 6: "todo", + 7: "todo", 8: "todo"}], + ["1592880", "iso-8859-1"], + ["1695964", "iso-8859-1"], + ["1463589", "iso-8859-1"], + ["1463589-utf", "UTF-8"], + ["IJ", "iso-8859-1"], + ["i68568", "iso-8859-1"], + ["i68568utf", "UTF-8"], + ["1706659", "iso-8859-1"], + ["digits-in-words", "iso-8859-1"], +// ["colons-in-words", "iso-8859-1"], Suggestion test only + ["ngram-utf-fix", "UTF-8"], + ["morph", "us-ascii", + {11: "todo", 12: "todo", 13: "todo", 14: "todo", 15: "todo", 16: "todo", + 17: "todo", 18: "todo", 19: "todo", 20: "todo", 21: "todo", 22: "todo", + 23: "todo", 24: "todo", 25: "todo", 26: "todo", 27: "todo"}], + ["1975530", "UTF-8"], + ["fullstrip", "iso-8859-1"], + ["iconv", "UTF-8"], + ["oconv", "UTF-8"], + ["encoding", "iso-8859-1", {1: "todo", 3: "todo"}], + ["korean", "UTF-8"], + ["opentaal-forbiddenword1", "UTF-8"], + ["opentaal-forbiddenword2", "UTF-8"], + ["opentaal-keepcase", "UTF-8"], + ["arabic", "UTF-8"], + ["2970240", "iso-8859-1"], + ["2970242", "iso-8859-1"], + ["breakoff", "iso-8859-1"], + ["opentaal-cpdpat", "iso-8859-1"], + ["opentaal-cpdpat2", "iso-8859-1"], + ["2999225", "iso-8859-1"], + ["onlyincompound2", "iso-8859-1"], + ["forceucase", "iso-8859-1"], + ["warn", "iso-8859-1"] +]; + +function do_get_file_by_line(file, charset) { + dump("getting file by line for file " + file.path + "\n"); + dump("using charset " + charset +"\n"); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(file, 0x1 /* READONLY */, + 0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF); + + let lis = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + lis.init(fis, charset, 1024, 0); + lis.QueryInterface(Ci.nsIUnicharLineInputStream); + + var val = {}; + while (lis.readLine(val)) { + yield val.value; + val = {}; + } +} + +function do_run_test(checker, name, charset, todo_good, todo_bad) { + dump("\n\n\n\n"); + dump("running test for " + name + "\n"); + if (!checker) { + do_throw("Need spell checker here!"); + } + + let good = do_get_file("data/" + name + ".good", true); + let bad = do_get_file("data/" + name + ".wrong", true); + let sug = do_get_file("data/" + name + ".sug", true); + + dump("Need some expected output\n") + do_check_true(good.exists() || bad.exists() || sug.exists()); + + dump("Setting dictionary to " + name + "\n"); + checker.dictionary = name; + + if (good.exists()) { + var good_counter = 0; + for (val in do_get_file_by_line(good, charset)) { + let todo = false; + good_counter++; + if (todo_good && todo_good[good_counter]) { + todo = true; + dump("TODO\n"); + } + + dump("Expect word " + val + " is spelled correctly\n"); + if (todo) { + todo_check_true(checker.check(val)); + } else { + do_check_true(checker.check(val)); + } + } + } + + if (bad.exists()) { + var bad_counter = 0; + for (val in do_get_file_by_line(bad, charset)) { + let todo = false; + bad_counter++; + if (todo_bad && todo_bad[bad_counter]) { + todo = true; + dump("TODO\n"); + } + + dump("Expect word " + val + " is spelled wrong\n"); + if (todo) { + todo_check_false(checker.check(val)); + } else { + do_check_false(checker.check(val)); + } + } + } + + // XXXkhuey test suggestions +} + +function run_test() { + let spellChecker = Cc["@mozilla.org/spellchecker/engine;1"]. + getService(Ci.mozISpellCheckingEngine); + + do_check_true(!!spellChecker, "Should have a spell checker"); + spellChecker.QueryInterface(Ci.mozISpellCheckingEngine); + let testdir = do_get_file("data/", false); + spellChecker.loadDictionariesFromDir(testdir); + + function do_run_test_closure(test) { + [name, charset, todo_good, todo_bad] = test; + do_run_test(spellChecker, name, charset, todo_good, todo_bad); + } + + tests.forEach(do_run_test_closure); +} diff --git a/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini new file mode 100644 index 000000000..39e55e51f --- /dev/null +++ b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' +support-files = data/** + +[test_hunspell.js] |