mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 02:19:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			297 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{  $Id$  }
 | 
						|
{
 | 
						|
 *****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *  This file is part of the Lazarus Component Library (LCL)                 *
 | 
						|
 *                                                                           *
 | 
						|
 *  See the file COPYING.modifiedLGPL, included in this distribution,        *
 | 
						|
 *  for details about the copyright.                                         *
 | 
						|
 *                                                                           *
 | 
						|
 *  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.                     *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************
 | 
						|
}
 | 
						|
unit IniPropStorage;
 | 
						|
 | 
						|
{$mode objfpc}{$H+}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  Classes, SysUtils, Forms, IniFiles, PropertyStorage;
 | 
						|
 | 
						|
Type
 | 
						|
  { TCustomIniPropStorage }
 | 
						|
 | 
						|
  TIniFileClass = Class of TCustomIniFile;
 | 
						|
  
 | 
						|
  TCustomIniPropStorage = Class(TFormPropertyStorage)
 | 
						|
  private
 | 
						|
    FCount : Integer;
 | 
						|
    FReadOnly : Boolean;
 | 
						|
    FIniFile: TCustomIniFile;
 | 
						|
    FIniFileName: String;
 | 
						|
    FIniSection: String;
 | 
						|
  protected
 | 
						|
    Function IniFileClass: TIniFileClass; virtual;
 | 
						|
    Function GetIniFileName: string; virtual;
 | 
						|
    Function RootSection: String; Override;
 | 
						|
    Property IniFile: TCustomIniFile Read FIniFile;
 | 
						|
  public
 | 
						|
    procedure StorageNeeded(ReadOnly: Boolean); override;
 | 
						|
    procedure FreeStorage; override;
 | 
						|
    function  DoReadString(const Section, Ident, Default: string): string; override;
 | 
						|
    procedure DoWriteString(const Section, Ident, Value: string); override;
 | 
						|
    procedure DoEraseSections(const ARootSection : String);override;
 | 
						|
  public
 | 
						|
    property IniFileName: String Read FIniFileName Write FIniFileName;
 | 
						|
    property IniSection: String Read FIniSection Write FIniSection;
 | 
						|
  end;
 | 
						|
  
 | 
						|
  { TIniPropStorage }
 | 
						|
  
 | 
						|
  TIniPropStorage = class(TCustomIniPropStorage)
 | 
						|
  Published
 | 
						|
    Property StoredValues;
 | 
						|
    property IniFileName;
 | 
						|
    property IniSection;
 | 
						|
    property Active;
 | 
						|
    property OnSavingProperties;
 | 
						|
    property OnSaveProperties;
 | 
						|
    property OnRestoringProperties;
 | 
						|
    property OnRestoreProperties;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
Procedure Register;
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
 | 
						|
Procedure Register;
 | 
						|
begin
 | 
						|
  RegisterComponents('Misc',[TIniPropStorage]);
 | 
						|
end;
 | 
						|
 | 
						|
{ Should move to strutils when 1.9.6 is out. }
 | 
						|
 | 
						|
function FindPart(const HelpWilds, InputStr: string): Integer;
 | 
						|
 | 
						|
var
 | 
						|
  I, J: Integer;
 | 
						|
  Diff: Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  I := Pos('?', HelpWilds);
 | 
						|
  if I = 0 then begin
 | 
						|
    { if no '?' in HelpWilds }
 | 
						|
    Result := Pos(HelpWilds, InputStr);
 | 
						|
    Exit;
 | 
						|
  end;
 | 
						|
  { '?' in HelpWilds }
 | 
						|
  Diff := Length(InputStr) - Length(HelpWilds);
 | 
						|
  if Diff < 0 then begin
 | 
						|
    Result := 0;
 | 
						|
    Exit;
 | 
						|
  end;
 | 
						|
  { now move HelpWilds over InputStr }
 | 
						|
  for I := 0 to Diff do begin
 | 
						|
    for J := 1 to Length(HelpWilds) do begin
 | 
						|
      if (InputStr[I + J] = HelpWilds[J]) or
 | 
						|
        (HelpWilds[J] = '?') then
 | 
						|
      begin
 | 
						|
        if J = Length(HelpWilds) then begin
 | 
						|
          Result := I + 1;
 | 
						|
          Exit;
 | 
						|
        end;
 | 
						|
      end
 | 
						|
      else Break;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
 | 
						|
 | 
						|
 function SearchNext(var Wilds: string): Integer;
 | 
						|
 { looking for next *, returns position and string until position }
 | 
						|
 begin
 | 
						|
   Result := Pos('*', Wilds);
 | 
						|
   if Result > 0 then Wilds := Copy(Wilds, 1, Result - 1);
 | 
						|
 end;
 | 
						|
 | 
						|
var
 | 
						|
  CWild, CInputWord: Integer; { counter for positions }
 | 
						|
  I, LenHelpWilds: Integer;
 | 
						|
  MaxInputWord, MaxWilds: Integer; { Length of InputStr and Wilds }
 | 
						|
  HelpWilds: string;
 | 
						|
begin
 | 
						|
  if Wilds = InputStr then begin
 | 
						|
    Result := True;
 | 
						|
    Exit;
 | 
						|
  end;
 | 
						|
  repeat { delete '**', because '**' = '*' }
 | 
						|
    I := Pos('**', Wilds);
 | 
						|
    if I > 0 then
 | 
						|
      Wilds := Copy(Wilds, 1, I - 1) + '*' + Copy(Wilds, I + 2, MaxInt);
 | 
						|
  until I = 0;
 | 
						|
  if Wilds = '*' then begin { for fast end, if Wilds only '*' }
 | 
						|
    Result := True;
 | 
						|
    Exit;
 | 
						|
  end;
 | 
						|
  MaxInputWord := Length(InputStr);
 | 
						|
  MaxWilds := Length(Wilds);
 | 
						|
  if IgnoreCase then begin { upcase all letters }
 | 
						|
    InputStr := AnsiUpperCase(InputStr);
 | 
						|
    Wilds := AnsiUpperCase(Wilds);
 | 
						|
  end;
 | 
						|
  if (MaxWilds = 0) or (MaxInputWord = 0) then begin
 | 
						|
    Result := False;
 | 
						|
    Exit;
 | 
						|
  end;
 | 
						|
  CInputWord := 1;
 | 
						|
  CWild := 1;
 | 
						|
  Result := True;
 | 
						|
  repeat
 | 
						|
    if InputStr[CInputWord] = Wilds[CWild] then begin { equal letters }
 | 
						|
      { goto next letter }
 | 
						|
      Inc(CWild);
 | 
						|
      Inc(CInputWord);
 | 
						|
      Continue;
 | 
						|
    end;
 | 
						|
    if Wilds[CWild] = '?' then begin { equal to '?' }
 | 
						|
      { goto next letter }
 | 
						|
      Inc(CWild);
 | 
						|
      Inc(CInputWord);
 | 
						|
      Continue;
 | 
						|
    end;
 | 
						|
    if Wilds[CWild] = '*' then begin { handling of '*' }
 | 
						|
      HelpWilds := Copy(Wilds, CWild + 1, MaxWilds);
 | 
						|
      I := SearchNext(HelpWilds);
 | 
						|
      LenHelpWilds := Length(HelpWilds);
 | 
						|
      if I = 0 then begin
 | 
						|
        { no '*' in the rest, compare the ends }
 | 
						|
        if HelpWilds = '' then Exit; { '*' is the last letter }
 | 
						|
        { check the rest for equal Length and no '?' }
 | 
						|
        for I := 0 to LenHelpWilds - 1 do begin
 | 
						|
          if (HelpWilds[LenHelpWilds - I] <> InputStr[MaxInputWord - I]) and
 | 
						|
            (HelpWilds[LenHelpWilds - I]<> '?') then
 | 
						|
          begin
 | 
						|
            Result := False;
 | 
						|
            Exit;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
        Exit;
 | 
						|
      end;
 | 
						|
      { handle all to the next '*' }
 | 
						|
      Inc(CWild, 1 + LenHelpWilds);
 | 
						|
      I := FindPart(HelpWilds, Copy(InputStr, CInputWord, MaxInt));
 | 
						|
      if I= 0 then begin
 | 
						|
        Result := False;
 | 
						|
        Exit;
 | 
						|
      end;
 | 
						|
      CInputWord := I + LenHelpWilds;
 | 
						|
      Continue;
 | 
						|
    end;
 | 
						|
    Result := False;
 | 
						|
    Exit;
 | 
						|
  until (CInputWord > MaxInputWord) or (CWild > MaxWilds);
 | 
						|
  { no completed evaluation }
 | 
						|
  if CInputWord <= MaxInputWord then Result := False;
 | 
						|
  if (CWild <= MaxWilds) and (Wilds[MaxWilds] <> '*') then Result := False;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
{ TCustomIniPropStorage }
 | 
						|
 | 
						|
function TCustomIniPropStorage.IniFileClass: TIniFileClass;
 | 
						|
begin
 | 
						|
  Result:=TIniFile;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCustomIniPropStorage.StorageNeeded(ReadOnly: Boolean);
 | 
						|
begin
 | 
						|
  If (FIniFile=Nil) or (ReadOnly<>FReadOnly) then
 | 
						|
    begin
 | 
						|
    If (FiniFile<>Nil) then
 | 
						|
      begin
 | 
						|
      // Force free.
 | 
						|
      FCount:=0;
 | 
						|
      FreeStorage;
 | 
						|
      end;
 | 
						|
    FReadOnly:=ReadOnly;
 | 
						|
    FInifile:=IniFileClass.Create(GetIniFileName);
 | 
						|
    end;
 | 
						|
  Inc(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCustomIniPropStorage.FreeStorage;
 | 
						|
begin
 | 
						|
  Dec(FCount);
 | 
						|
  If FCount<=0 then
 | 
						|
    begin
 | 
						|
    FCount:=0;
 | 
						|
    FreeAndNil(FIniFile);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
function TCustomIniPropStorage.GetIniFileName: string;
 | 
						|
begin
 | 
						|
  If (FIniFileName<>'') then
 | 
						|
    Result:=FIniFileName
 | 
						|
  else
 | 
						|
{$ifdef unix}
 | 
						|
    Result:=IncludeTrailingPathDelimiter(GetEnvironmentVariable('HOME'))
 | 
						|
            +'.'+ExtractFileName(Application.ExeName);
 | 
						|
 | 
						|
{$else}
 | 
						|
    Result:=ChangeFileExt(Application.ExeName,'.ini');
 | 
						|
{$endif}
 | 
						|
end;
 | 
						|
 | 
						|
function TCustomIniPropStorage.RootSection: String;
 | 
						|
begin
 | 
						|
  if (FIniSection='') then
 | 
						|
    Result:=inherited RootSection
 | 
						|
  else
 | 
						|
    Result:=FIniSection;
 | 
						|
end;
 | 
						|
 | 
						|
function TCustomIniPropStorage.DoReadString(const Section, Ident, Default: string): string;
 | 
						|
begin
 | 
						|
  Result:=FIniFile.ReadString(Section, Ident, Default);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCustomIniPropStorage.DoWriteString(const Section, Ident, Value: string);
 | 
						|
begin
 | 
						|
  FIniFile.WriteString(Section, Ident, Value);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCustomIniPropStorage.DoEraseSections(const ARootSection: String);
 | 
						|
 | 
						|
var
 | 
						|
  Lines: TStrings;
 | 
						|
  I: Integer;
 | 
						|
begin
 | 
						|
  Lines := TStringList.Create;
 | 
						|
  try
 | 
						|
    FInifile.ReadSections(Lines);
 | 
						|
    for I := 0 to Lines.Count - 1 do begin
 | 
						|
      if (Lines[I] = IniSection) or
 | 
						|
        (IsWild(Lines[I], IniSection + '.*', False) or
 | 
						|
        IsWild(Lines[I], IniSection + '\*', False)) then
 | 
						|
        FInifile.EraseSection(Lines[I]);
 | 
						|
    end;
 | 
						|
  finally
 | 
						|
    Lines.Free;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
end.
 |