{
ZHunSpellers.pas a Hunspell wrapper
License
Interface module with Hunspell dynamic library.
Based on code found in many places on the Lazarus forum and Github.
It is intended to be freely used by anyone for any purpose.
OlegZ 2020
Extract from the article.
The ZHunSpellers module contains the code of the THunSpeller class , through the methods of which access
to the functionality of the hunspell DLL library is provided , the attachment of which will be performed
automatically when the first instance of the class is created.
By default, the DLL file name is libhunspell-1.7_32.dll or libhunspell-1.7_64.dll ,
and the path to the library is defined according to standard Windows rules .
If you need to change the default, you should define the DefaultDLLPath and
DefaultHunspellLibName variables before creating
the first instance of the THunSpeller class .
In order not to be tied to the DLLs I found, I decided to try compiling hunspell myself .
To work with C++, in which the libraries are written, I already had MSYS + MinGW GCC v9.2.0 installed,
as well as IDE Code::Blocks 20.03. After that, after downloading the hunspell source code from the project site ,
I created a Code::Blocks DLL project based on the files in the src/hunspell directory from the project's master branch on Github.
After that, it only remained to compile the project, not forgetting to define BUILDING_LIBHUNSPELL ,
and when linking, set the -static-libgcc and -static-libstdc++ flagsto exclude dynamic linking of GCC DLLs.
By following these procedures on 32-bit and 64-bit systems, I got the necessary DLLs based on the current version
of hunspell 1.7 - libhunspell-1.7_32.dll and libhunspell-1.7_64.dll , respectively.
Machine automatic translation from Russian to English
Source of unit and article in Russian;
http://electroanalysis.ucoz.net/publ/zametki/proverka_orfografii_spell_checking_v_vashej_programme/3-1-0-13
}
unit ZHunSpellers;//ZHunSpellers.pas
{$mode objfpc}{$H+}
interface
uses
windows,
Classes, SysUtils,
LazUTF8;
{$Inline on}
//----------------------------------------------------------------------------------------
const
// Default DLL file name
{$IfDef WIN32}
cDefaultHunspellLibName = 'libhunspell-1.7_32.dll';//Name of hunspell DLL 32bit
{$Else}
{$IfDef WIN64}
cDefaultHunspellLibName = 'libhunspell-1.7_64.dll';//Name of hunspell DLL 64bit
{$Else}
{$Error Bad target OS}
{$EndIf}
{$EndIf}
//----------------------------------------------------------------------------------------
// Exception handler for module errors
type
EHunSpellerError = class(Exception)
end;
//----------------------------------------------------------------------------------------
type
{ THunSpeller }
THunSpeller = class
private
FDictionaryFullName: string; // The full name of the dic file of the loaded dictionary
FSpeller: Pointer; // Pointer to speller instance - result of Hunspell_create
// Returns True if the speller is ready to go
function GetReady: boolean; inline;
// Returns the encoding of the loaded dictionary
function GetDictEncoding: string;
// Internal procedure for executing Hunspell_suggest, Hunspell_analyze and Hunspell_stem functions
procedure iProcWithList(aFunc: pointer; const aWord: string; aList: TStrings);
public
// Creating a speller without loading a dictionary
constructor Create;
// Creating a speller loading a dictionary whose file is named aFullDictName
// The affix file (aff) is considered to be in the same directory
constructor Create(const aFullDictName: string);
destructor Destroy; override;
// Loading dictionary from file aFullDictName, the previous dictionary is closed
procedure OpenDictionary(const aFullDictName: string);
// Closing the loaded dictionary
procedure CloseDictionary;
//----------- DLL function wrappers -----------
// Checking the word aWord, returns True if the word is correct
function Spell(const aWord: string): boolean;
// List returns variants of the wrong word aWard
// If there are no options, then an empty list is returned
procedure Suggest(const aWord: string; aList: TStrings);
// In the list aList, the results of the morphological analysis of the word aWard are returned
procedure Analyze(const aWord: string; aList: TStrings);
// in the list aList return variants of the stem of the word aWard
procedure Stem(const aWord: string; aList: TStrings);
// The word aWord is added to the loaded (run-time) dictionary
procedure Add(const aWord: string);
// The word aWard is added to the loaded (run-time) dictionary
// Inflected forms of the word aWard are formed similarly to the dictionary word aExample
procedure AddWithAffix(const aWord, aExample: string);
// The word aWord is removed from the loaded (run-time) dictionary
procedure Remove(const aWord: string);
property Ready: boolean read GetReady;
property DictionaryFullName: string read FDictionaryFullName;
property DictEncoding: string read GetDictEncoding;
end;
//----------------------------------------------------------------------------------------
var
DefaultDLLPath: string = ''; // DLL file search path
DefaultHunspellLibName: string = cDefaultHunspellLibName; // DLL file name
// Returns the full filename of the loaded DLL
function GetDLLFullName: string;
property DLLFullName: string read GetDLLFullName;
//****************************************************************************************
//****************************************************************************************
implementation
//----------------------------------------------------------------------------------------
// DLL Library control
//----------------------------------------------------------------------------------------
var
FDLLFullName: string; // Fully qualified filename of the loaded DLL
FLibHandle: THandle = NilHandle; // Descriptor DLL-library
FAllLibProcLoaded: boolean = false; // = True if the addresses of all used functions were successfully loaded
// addresses of required DLL functions
HS_create: pointer;
HS_destroy: pointer;
HS_spell: pointer;
HS_suggest: pointer;
HS_analyze: pointer;
HS_stem: pointer;
HS_free_list: pointer;
HS_add: pointer;
HS_add_with_affix: pointer;
HS_remove: pointer;
HS_get_dic_encoding: pointer;
FSpellersCount: integer = 0; // counter of active spellers
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// Returns the full filename of the loaded DLL
function GetDLLFullName: string;
begin
Result := FDLLFullName;
end;
// Internal function to get the address of the exported function by name
// An EHunSpellerError trap is generated on error
function iGetProcAddr(const aFuncName: string): pointer;
begin
Result := system.GetProcAddress(FLibHandle, aFuncName);
if not Assigned(Result) then
raise EHunSpellerError.CreateFmt('Failed to find functions "%s" in "%s"',
[aFuncName, FDLLFullName]);
end;
// Getting addresses of all used DLL functions
procedure SetupFuncVars;
begin
HS_create := iGetProcAddr('Hunspell_create');
HS_destroy := iGetProcAddr('Hunspell_destroy');
HS_spell := iGetProcAddr('Hunspell_spell');
HS_suggest := iGetProcAddr('Hunspell_suggest');
HS_analyze := iGetProcAddr('Hunspell_analyze');
HS_stem := iGetProcAddr('Hunspell_stem');
HS_free_list := iGetProcAddr('Hunspell_free_list');
HS_add := iGetProcAddr('Hunspell_add');
HS_add_with_affix := iGetProcAddr('Hunspell_add_with_affix');
HS_remove := iGetProcAddr('Hunspell_remove');
HS_get_dic_encoding := iGetProcAddr('Hunspell_get_dic_encoding');
FAllLibProcLoaded := true;
end;
// DLL loading
procedure OpenLib;
const
cBufLen = 1024;
var
s: string;
begin
s := DefaultDLLPath + DefaultHunspellLibName;
FLibHandle := system.LoadLibrary(s);
if FLibHandle = NilHandle then
raise EHunSpellerError.CreateFmt('Failed to load library: %s', [FDLLFullName]);
SetLength(s, cBufLen);
GetModuleFileName(FLibHandle, @s[1], cBufLen);
SetLength(s, strlen(@s[1]));
FDLLFullName := WinCPToUTF8(s);
SetupFuncVars;
end;
// DLL unloading
procedure CloseLib;
begin
if (FLibHandle <> NilHandle) then begin
system.FreeLibrary(FLibHandle);
FLibHandle := NilHandle;
FAllLibProcLoaded := false;
end;
end;
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{ THunSpeller }
// Returns True if the speller instance is ready to go
function THunSpeller.GetReady: boolean;
begin
Result := (FLibHandle <> NilHandle) // DLL loaded
and FAllLibProcLoaded // All used functions loaded
and (FSpeller <> nil); // Speller created
end;
//----------------------------------------------------------------------------------------
// Returns the encoding type of the dictionary file
function THunSpeller.GetDictEncoding: string;
//hunspell.h -> char* Hunspell_get_dic_encoding(Hunhandle* pHunspell);
type
THSFunc_get_dic_encoding = function(spell: Pointer): PChar; cdecl;
var
p: pchar;
begin
if not Ready then exit('Speller is not ready');
p := THSFunc_get_dic_encoding(HS_get_dic_encoding)(FSpeller);
if p = nil then exit('Encoding string not found');
SetLength(Result, strlen(p));
Move(p^, Result[1], strlen(p));
end;
//----------------------------------------------------------------------------------------
// creating a speller instance without opening a dictionary
constructor THunSpeller.Create;
begin
if FLibHandle = NilHandle then
OpenLib;
end;
//----------------------------------------------------------------------------------------
// Creating a speller instance with dictionary opening
constructor THunSpeller.Create(const aFullDictName: string);
begin
if FLibHandle = NilHandle then
OpenLib;
OpenDictionary(aFullDictName);
end;
//----------------------------------------------------------------------------------------
destructor THunSpeller.Destroy;
begin
CloseDictionary;
inherited Destroy;
end;
//----------------------------------------------------------------------------------------
// Opening a dictionary from aFullDictName file,
// previously opened dictionary is closed beforehand
procedure THunSpeller.OpenDictionary(const aFullDictName: string);
//hunspell.h -> Hunhandle* Hunspell_create(const char* affpath, const char* dpath);
type
THSFunc_create = function(aff_file: PChar; dict_file: PChar): Pointer; cdecl;
var
FullAffName : string;
begin
CloseDictionary;
FDictionaryFullName := aFullDictName;
FullAffName := UTF8Copy(aFullDictName, 1, UTF8Length(aFullDictName) - 3) + 'aff';
FSpeller := THSFunc_create(HS_create)(PChar(UTF8ToWinCP(FullAffName)), PChar(UTF8ToWinCP(aFullDictName)));
if FSpeller = nil then
raise EHunSpellerError.CreateFmt('Failed to open Dictionary "%s"', [aFullDictName]);
inc(FSpellersCount);
end;
//----------------------------------------------------------------------------------------
// Dictionary closure
procedure THunSpeller.CloseDictionary;
//hunspell.h -> Hunspell_destroy(Hunhandle* pHunspell);
type
THSFunc_destroy = procedure(spell: Pointer); cdecl;
begin
if Ready then begin
THSFunc_destroy(HS_destroy)(FSpeller);
FSpeller := nil;
dec(FSpellersCount);
end;
end;
//----------------------------------------------------------------------------------------
// Checking the word aWord, returns True if the word is correct
function THunSpeller.Spell(const aWord: string): boolean;
//hunspell.h -> int Hunspell_spell(Hunhandle* pHunspell, const char* );
type
THSFunc_spell = function(spell: Pointer; word: PChar): Boolean; cdecl;
begin
if Ready then
Result := THSFunc_spell(HS_spell)(FSpeller, PChar(aWord))
else
Result := false;
end;
//----------------------------------------------------------------------------------------
// Private procedure for calling DLL functions that return a result as a list of words:
// Hunspell_suggest, Hunspell_analyze and Hunspell_stem
procedure THunSpeller.iProcWithList(aFunc: pointer; const aWord: string; aList: TStrings);
type
THSFuncWithList = function(spell: Pointer; out slst: PPChar; word: PChar): Integer; cdecl;
//hunspell.h -> void Hunspell_free_list(Hunhandle* pHunspell, char*** slst, int n);
THSFunc_free_list = procedure(spell: Pointer; var slst: PPChar; n: integer); cdecl;
var
i, len: Integer;
SugList, Words: PPChar;
begin
aList.Clear;
if not Ready then
exit;
try
len := THSFuncWithList(aFunc)(FSpeller, SugList, PChar(aWord));
Words := SugList;
for i := 1 to len do begin
aList.Add(PChar(Words^));
Inc(Words);
end;
finally
// Freeing the list of words
THSFunc_free_list(HS_free_list)(FSpeller, SugList, len);
end;
end;
//----------------------------------------------------------------------------------------
// List returns variants of the wrong word aWard
// If there are no options, then an empty list is returned
procedure THunSpeller.Suggest(const aWord: string; aList: TStrings);
//hunspell.h -> int Hunspell_suggest(Hunhandle* pHunspell, char*** slst, const char* word);
begin
iProcWithList(HS_suggest, aWord, aList);
end;
//----------------------------------------------------------------------------------------
// In the list aList, the results of the morphological analysis of the word aWard are returned
procedure THunSpeller.Analyze(const aWord: string; aList: TStrings);
//hunspell.h -> int Hunspell_analyze(Hunhandle* pHunspell, char*** slst, const char* word);
begin
iProcWithList(HS_analyze, aWord, aList);
end;
//----------------------------------------------------------------------------------------
// in the list aList return variants of the stem of the word aWard
procedure THunSpeller.Stem(const aWord: string; aList: TStrings);
//hunspell.h -> int Hunspell_stem(Hunhandle* pHunspell, char*** slst, const char* word);
begin
iProcWithList(HS_stem, aWord, aList);
end;
//----------------------------------------------------------------------------------------
// The word aWord is added to the loaded (run-time) dictionary
procedure THunSpeller.Add(const aWord: string);
//hunspell.h -> int Hunspell_add(Hunhandle* pHunspell, const char* word);
type
THSFunc_add = function(spell: Pointer; word: PChar): Integer; cdecl;
begin
if Ready then
THSFunc_add(HS_add)(FSpeller, Pchar(aWord));
end;
//----------------------------------------------------------------------------------------
// The word aWord is added to the loaded (run-time) dictionary
// Inflected forms of the word aWard are formed similarly to the dictionary word Example
procedure THunSpeller.AddWithAffix(const aWord, aExample: string);
//hunspell.h -> int Hunspell_add_with_affix(Hunhandle* pHunspell, const char* word, const char* example);
type
THSFunc_add_with_affix = function(spell: Pointer; word: PChar; example: PChar): Integer; cdecl;
begin
if Ready then
THSFunc_add_with_affix(HS_add_with_affix)(FSpeller, PChar(aWord), PChar(aExample));
end;
//----------------------------------------------------------------------------------------
// The word aWord is removed from the loaded (run-time) dictionary
procedure THunSpeller.Remove(const aWord: string);
//hunspell.h -> int Hunspell_remove(Hunhandle* pHunspell, const char* word);
type
THSFunc_remove = function(spell: Pointer; word: PChar): Integer; cdecl;
begin
if Ready then
THSFunc_remove(HS_remove)(FSpeller, Pchar(aWord));
end;
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
finalization
// Unload DLL on program exit
CloseLib;
// Checking the completion of all speller instances
if FSpellersCount > 0 then
raise EHunSpellerError.CreateFmt('Not disposed spellers: %d', [FSpellersCount]);
end.
{
Help for ZHunSpellers.pas
--------------------------
EHunSpellerError
--------------------------
Declaration: Exception handler for module errors
type EHunSpellerError = class(Exception)
Inheritance
EHunSpellerError
Exception handler for module errors
|
Exception
?
TObject
--------------------------
THunSpeller
--------------------------
type THunSpeller = class
public
constructor Create();Creating an instance of the THunSpeller class
destructor Destroy; override;Closes the opened dictionary and removes the class instance
procedure OpenDictionary();Loading a dictionary from a file
procedure CloseDictionary; Closing a loaded dictionary
function Spell();Performs a word check
procedure Suggest();Returns spellings of a word in a list
procedure Analyze();Performs morphological analysis of a word
procedure Stem();Returns word stem variants
procedure Add();Adding a word to the loaded (run-time) dictionary
procedure AddWithAffix();Adding a word to the loaded (run-time) dictionary
procedure Remove();Removes a word from the loaded (run-time) dictionary
property Ready: Boolean; [r] Speller ready to go
property DictionaryFullName: string; [r] Returns the fully qualified dic filename of the loaded dictionary
property DictEncoding: string; [r] Returns the encoding of the loaded dictionary
end;
Inheritance
THunSpeller A class that implements the interface with the dynamic library HunSpell
|
TObject
Description
The THunSpellers class instantiates a speller associated with a particular dictionary file and provides access to the Hunspell dynamic library functions.
Remark: When the first instance of the class is created, the dynamic library is loaded.
------------------------
GetDLLFullName
------------------------
Returns the full filename of the loaded DLL
Declaration
function GetDLLFullName: string;
}