doublecmd/src/udsxmodule.pas

413 lines
No EOL
11 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
(DSX) Search plugin API implementation.
DSX - Double commander Search eXtentions.
Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
}
unit uDsxModule;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, dynlibs, LCLProc, DsxPlugin, uClassesEx, uDCUtils,
uOSUtils, uXmlConfig;
type
{ TDsxModule }
TDsxModule = class
protected
SStartSearch: TSStartSearch;
SStopSearch: TSStopSearch;
SAddFileProc: TSAddFileProc;
SUpdateStatusProc: TSUpdateStatusProc;
SInit: TSInit;
SFinalize: TSFinalize;
private
FPluginNr: integer;
FModuleHandle: TLibHandle; // Handle to .DLL or .so
function GIsLoaded: boolean;
public
Name: string;
FileName: string;
Descr: string;
//---------------------
constructor Create;
destructor Destroy; override;
//---------------------
function LoadModule: boolean;
procedure UnloadModule;
//---------------------
function CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer;
procedure CallStartSearch(SearchRec: TDsxSearchRecord);
procedure CallStopSearch;
procedure CallFinalize;
//---------------------
property IsLoaded: boolean read GIsLoaded;
property ModuleHandle: TLibHandle read FModuleHandle write FModuleHandle;
end;
{ TDSXModuleList }
TDSXModuleList = class
private
Flist: TStringList;
function GetCount: integer;
public
//---------------------
constructor Create;
destructor Destroy; override;
//---------------------
procedure Clear;
procedure Load(Ini: TIniFileEx); overload;
procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload;
procedure Save(Ini: TIniFileEx); overload;
procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload;
procedure DeleteItem(Index: integer);
//---------------------
function Add(Item: TDSXModule): integer; overload;
function Add(FileName: string): integer; overload;
function Add(AName, FileName, Descr: string): integer; overload;
//---------------------
procedure Assign(OtherList: TDSXModuleList);
//---------------------
function IsLoaded(AName: string): boolean; overload;
function IsLoaded(Index: integer): boolean; overload;
function LoadModule(AName: string): boolean; overload;
function LoadModule(Index: integer): boolean; overload;
//---------------------
function GetDSXModule(Index: integer): TDSXModule; overload;
function GetDSXModule(AName: string): TDSXModule; overload;
//---------------------
property Count: integer read GetCount;
end;
implementation
uses
uGlobs, uGlobsPaths;
const
DsxIniFileName = 'dsx.ini';
{ TDsxModule }
function TDsxModule.GIsLoaded: boolean;
begin
Result := FModuleHandle <> 0;
end;
constructor TDsxModule.Create;
begin
FModuleHandle := 0;
inherited Create;
end;
destructor TDsxModule.Destroy;
begin
if GIsLoaded then
UnloadModule;
inherited Destroy;
end;
function TDsxModule.LoadModule: boolean;
begin
FModuleHandle := mbLoadLibrary(Self.FileName);
Result := (FModuleHandle <> 0);
if FModuleHandle = 0 then
exit;
SStopSearch := TSStopSearch(GetProcAddress(FModuleHandle, 'StopSearch'));
SStartSearch := TSStartSearch(GetProcAddress(FModuleHandle, 'StartSearch'));
SInit := TSInit(GetProcAddress(FModuleHandle, 'Init'));
SFinalize := TSFinalize(GetProcAddress(FModuleHandle, 'Finalize'));
end;
procedure TDsxModule.UnloadModule;
begin
if Assigned(SFinalize) then
SFinalize(FPluginNr);
if FModuleHandle <> 0 then
FreeLibrary(FModuleHandle);
FModuleHandle := 0;
SStartSearch := nil;
SStopSearch := nil;
SInit := nil;
SFinalize := nil;
end;
function TDsxModule.CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer;
var
dps: TDsxDefaultParamStruct;
begin
if Assigned(SInit) then
begin
dps.DefaultIniName := gpCfgDir + DsxIniFileName;
dps.PluginInterfaceVersionHi := 0;
dps.PluginInterfaceVersionLow := 10;
dps.size := SizeOf(TDsxDefaultParamStruct);
FPluginNr := Sinit(@dps, pAddFileProc, pUpdateStatus);
Result := FPluginNr;
end;
end;
procedure TDsxModule.CallStartSearch(SearchRec: TDsxSearchRecord);
begin
if Assigned(SStartSearch) then
SStartSearch(FPluginNr, @SearchRec);
end;
procedure TDsxModule.CallStopSearch;
begin
if Assigned(SStopSearch) then
SStopSearch(FPluginNr);
end;
procedure TDsxModule.CallFinalize;
begin
if Assigned(SFinalize) then
SFinalize(FPluginNr);
end;
{ TDSXModuleList }
function TDSXModuleList.GetCount: integer;
begin
if Assigned(Flist) then
Result := Flist.Count
else
Result := 0;
end;
constructor TDSXModuleList.Create;
begin
Flist := TStringList.Create;
end;
destructor TDSXModuleList.Destroy;
begin
Clear;
FreeAndNil(Flist);
inherited Destroy;
end;
procedure TDSXModuleList.Clear;
begin
while Flist.Count > 0 do
begin
TDSXModule(Flist.Objects[0]).Free;
Flist.Delete(0);
end;
end;
procedure TDSXModuleList.Load(Ini: TIniFileEx);
var
xCount, I: integer;
tmp: string;
begin
Self.Clear;
xCount := Ini.ReadInteger('Search Plugins', 'PluginCount', 0);
if xCount = 0 then
Exit;
for i := 0 to xCount - 1 do
begin
tmp := Ini.ReadString('Search Plugins', 'Plugin' + IntToStr(I + 1) + 'Name', '');
Flist.AddObject(UpCase(tmp), TDSXModule.Create);
TDSXModule(Flist.Objects[I]).Name := tmp;
TDSXModule(Flist.Objects[I]).Descr :=
Ini.ReadString('Search Plugins', 'Plugin' + IntToStr(I + 1) + 'Description', '');
TDSXModule(Flist.Objects[I]).FileName :=
GetCmdDirFromEnvVar(Ini.ReadString('Search Plugins', 'Plugin' + IntToStr(I + 1) + 'Path', ''));
end;
end;
procedure TDSXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode);
var
AName, APath: String;
ADsxModule: TDSXModule;
begin
Clear;
ANode := ANode.FindNode('DsxPlugins');
if Assigned(ANode) then
begin
ANode := ANode.FirstChild;
while Assigned(ANode) do
begin
if ANode.CompareName('DsxPlugin') = 0 then
begin
if AConfig.TryGetValue(ANode, 'Name', AName) and
AConfig.TryGetValue(ANode, 'Path', APath) then
begin
ADsxModule := TDsxModule.Create;
Flist.AddObject(UpCase(AName), ADsxModule);
ADsxModule.Name := AName;
ADsxModule.FileName := GetCmdDirFromEnvVar(APath);
ADsxModule.Descr := AConfig.GetValue(ANode, 'Description', '');
end
else
DebugLn('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.');
end;
ANode := ANode.NextSibling;
end;
end;
end;
procedure TDSXModuleList.Save(Ini: TIniFileEx);
var
i: integer;
begin
Ini.EraseSection('Search Plugins');
Ini.WriteInteger('Search Plugins', 'PluginCount', Flist.Count);
for i := 0 to Flist.Count - 1 do
begin
Ini.WriteString('Search Plugins', 'Plugin' + IntToStr(I + 1) + 'Name',
TDSXModule(Flist.Objects[I]).Name);
Ini.WriteString('Search Plugins', 'Plugin' + IntToStr(I + 1) +
'Description', TDSXModule(Flist.Objects[I]).Descr);
Ini.WriteString('Search Plugins', 'Plugin' + IntToStr(I + 1) + 'Path',
SetCmdDirAsEnvVar(TDSXModule(Flist.Objects[I]).FileName));
end;
end;
procedure TDSXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode);
var
i: Integer;
SubNode: TXmlNode;
begin
ANode := AConfig.FindNode(ANode, 'DsxPlugins', True);
AConfig.ClearNode(ANode);
for i := 0 to Flist.Count - 1 do
begin
SubNode := AConfig.AddNode(ANode, 'DsxPlugin');
AConfig.AddValue(SubNode, 'Name', TDSXModule(Flist.Objects[I]).Name);
AConfig.AddValue(SubNode, 'Path', SetCmdDirAsEnvVar(TDSXModule(Flist.Objects[I]).FileName));
AConfig.AddValue(SubNode, 'Description', TDSXModule(Flist.Objects[I]).Descr);
end;
end;
procedure TDSXModuleList.DeleteItem(Index: integer);
begin
if (Index > -1) and (Index < Flist.Count) then
begin
TDSXModule(Flist.Objects[Index]).Free;
Flist.Delete(Index);
end;
end;
function TDSXModuleList.Add(Item: TDSXModule): integer;
begin
Result := Flist.AddObject(UpCase(item.Name), Item);
end;
function TDSXModuleList.Add(FileName: string): integer;
var
s: string;
begin
s := ExtractFileName(FileName);
if pos('.', s) > 0 then
Delete(s, pos('.', s), length(s));
Result := Flist.AddObject(UpCase(s), TDSXModule.Create);
TDSXModule(Flist.Objects[Result]).Name := s;
TDSXModule(Flist.Objects[Result]).FileName := FileName;
end;
function TDSXModuleList.Add(AName, FileName, Descr: string): integer;
begin
Result := Flist.AddObject(UpCase(AName), TDSXModule.Create);
TDSXModule(Flist.Objects[Result]).Name := AName;
TDSXModule(Flist.Objects[Result]).Descr := Descr;
TDSXModule(Flist.Objects[Result]).FileName := FileName;
end;
procedure TDSXModuleList.Assign(OtherList: TDSXModuleList);
var
i: Integer;
begin
Clear;
for i := 0 to OtherList.Flist.Count - 1 do
begin
with TDSXModule(OtherList.Flist.Objects[I]) do
Add(Name, FileName, Descr);
end;
end;
function TDSXModuleList.IsLoaded(AName: string): boolean;
var
x: integer;
begin
x := Flist.IndexOf(AName);
if x = -1 then
Result := False
else
begin
Result := GetDSXModule(x).IsLoaded;
end;
end;
function TDSXModuleList.IsLoaded(Index: integer): boolean;
begin
Result := GetDSXModule(Index).IsLoaded;
end;
function TDSXModuleList.LoadModule(AName: string): boolean;
var
x: integer;
begin
x := Flist.IndexOf(UpCase(AName));
if x = -1 then
Result := False
else
begin
Result := GetDSXModule(x).LoadModule;
end;
end;
function TDSXModuleList.LoadModule(Index: integer): boolean;
begin
Result := GetDSXModule(Index).LoadModule;
end;
function TDSXModuleList.GetDSXModule(Index: integer): TDSXModule;
begin
Result := TDSXModule(Flist.Objects[Index]);
end;
function TDSXModuleList.GetDSXModule(AName: string): TDSXModule;
var
tmp: integer;
begin
tmp := Flist.IndexOf(upcase(AName));
if tmp > -1 then
Result := TDSXModule(Flist.Objects[tmp]);
end;
end.