{ $Id$ This file is part of the Free Component Library (FCL) Copyright (c) 1999-2000 by Michael A. Hess Old inifiles unit adapted for fpcmake 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 MakeIni; {$mode objfpc} {$H+} interface uses Classes; type { TIniFile class } TIniFile = class(TObject) private FEscapeLineFeeds : Boolean; FFileName : string; FStream : TStream; FFileBuffer : TStringList; function GetName(const line : string) : string; function GetValue(const line, name : string) : string; function IsComment(const line : string) : boolean; function IsSection(const line : string) : boolean; function GetSectionIndex(const section : string) : integer; protected procedure SetFileName(const fn:string); procedure SetStream(s:TStream); procedure LoadFromFile; procedure SaveToFile; procedure LoadFromStream; procedure SaveToStream; public constructor Create(const theFileName : string); constructor Create(s:TStream); destructor Destroy; override; procedure DeleteKey(const section, ident : string); procedure EraseSection(const section : string); function ReadBool(const section, ident : string; defaultValue : boolean) : boolean; function ReadInteger(const section, ident : string; defaultValue : longint) : longint; procedure ReadSection(const section : string; strings : TStrings); procedure ReadSections(strings : TStrings); procedure ReadSectionValues(const section : string; strings : TStrings); procedure ReadSectionRaw(const section : string; strings : TStrings); function ReadString(const section, ident, defaultValue : string) : string; procedure WriteBool(const section, ident : string; value : boolean); procedure WriteInteger(const section, ident : string; value : longint); procedure WriteString(const section, ident, value : string); property FileName : String read FFileName; property EscapeLineFeeds : Boolean Read FEscapeLineFeeds Write FEscapeLineFeeds default false; end; implementation uses SysUtils; const brackets : array[0..1] of Char = ('[', ']'); separator : Char = '='; comment : Char = ';'; { TIniFile } constructor TIniFile.Create(const theFileName : string); begin FFileName := theFileName; FStream:=nil; FEscapeLineFeeds:=False; FFileBuffer := TStringList.Create; if FileExists(fileName) then LoadFromFile; end; constructor TIniFile.Create(s:TStream); begin FFileName := ''; FStream:=s; FEscapeLineFeeds:=False; FFileBuffer := TStringList.Create; LoadFromStream; end; destructor TIniFile.Destroy; begin FFileBuffer.Free; end; function TIniFile.GetName(const line : string) : string; var index,index2 : integer; begin Result := ''; index := Pos(separator, line); if index <> 0 then begin index2:=Pos(comment, line); if (index2=0) or (index2>index) then result := Trim(Copy(line, 1, index - 1)); end; end; function TIniFile.GetValue(const line, name : string) : string; var index1,index2,index3 : integer; begin result := ''; if (line <> '') and (name <> '') then begin index1 := Pos(name, line); index2 := Pos(separator, line); index3 := Pos(comment, line); if index3=0 then index3:=MaxInt; if (index1 <> 0) and (index2 <> 0) and (index2 > index1) then result := Trim(Copy(line, index2 + 1, index3)); end; end; function TIniFile.IsSection(const line : string) : boolean; var str : string; begin result := False; if line <> '' then begin str := Trim(line); if (str<>'') and (str[1] = brackets[0]) and (str[Length(str)] = brackets[1]) then result := True; end; end; function TIniFile.IsComment(const line : string) : boolean; var str : string; begin result := False; if line <> '' then begin str := Trim(line); result := (str<>'') and (str[1]=comment); end; end; function TIniFile.GetSectionIndex(const section : string) : integer; begin result := FFileBuffer.IndexOf(brackets[0] + section + brackets[1]); end; { Load/Save } procedure TIniFile.SetFileName(const fn:string); begin FFileName:=fn; end; procedure TIniFile.SetStream(s:TStream); begin FStream:=s; end; procedure TIniFile.LoadFromFile; begin if FFileName<>'' then FFileBuffer.LoadFromFile(FFileName); end; procedure TIniFile.SaveToFile; begin if FFileName<>'' then FFileBuffer.SaveToFile(FFileName); end; procedure TIniFile.LoadFromStream; begin if assigned(FStream) then FFileBuffer.LoadFromStream(FStream); end; procedure TIniFile.SaveToStream; begin if assigned(FStream) then FFileBuffer.SaveToStream(FStream); end; { Read all Names of one Section } procedure TIniFile.ReadSection(const section : string; strings : TStrings); var index : integer; name : string; begin strings.BeginUpdate; try strings.Clear; if FFileBuffer.Count > 0 then begin index := GetSectionIndex(section); if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do begin name := GetName(FFileBuffer[index]); if name <> '' then strings.Add(name); Inc(index); end; end; end; finally strings.EndUpdate; end; end; { Read all Sections of the Ini-File } procedure TIniFile.ReadSections(strings : TStrings); var index : integer; section : string; begin strings.BeginUpdate; try strings.Clear; if FFileBuffer.Count > 0 then begin index := 0; while (index < FFileBuffer.Count) do begin if IsSection(FFileBuffer[index]) then begin section := Trim(FFileBuffer[index]); Delete(section, 1, 1); Delete(section, Length(section), 1); strings.Add(Trim(section)); end; Inc(index); end; end; finally strings.EndUpdate; end; end; { Reads a String-Value of "ident" in one "section". The result is "defaultValue" if o section doesn't exists o ident doesn't exists o ident doesn't have any assigned value } function TIniFile.ReadString(const section, ident, defaultValue : string) : string; var index : integer; value : string; begin result := defaultValue; if FFileBuffer.Count > 0 then begin index := GetSectionIndex(section); if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do begin if CompareText(GetName(FFileBuffer[index]),ident)=0 then begin value := GetValue(FFileBuffer[index], ident); if value <> '' then begin result := value; if EscapeLineFeeds and (result[length(result)]='\') then begin inc(index); while (index < FFileBuffer.Count) and (result[length(result)]='\') do begin result:=Copy(result,1,length(result)-1)+Trim(FFileBuffer[index]); inc(index); end; end; end; break; end; Inc(index); end; end; end; end; { Reads an Integer-Value of Ident in one Section } function TIniFile.ReadInteger(const section, ident : string; defaultValue : longint) : longint; var intStr : string; begin intStr := ReadString(section, ident, ''); { convert a Hex-Value } if (Length(intStr) > 2) and (intStr[1] = '0') and ((intStr[2] = 'X') or (intStr[2] = 'x')) then intStr := '$' + Copy(intStr, 3, Maxint); result := StrToIntDef(intStr, defaultValue); end; { Reads a Bool-Value of Ident in one Section } function TIniFile.ReadBool(const section, ident : string; defaultValue : boolean) : boolean; begin result := ReadInteger(section, ident, Ord(defaultValue)) <> 0; end; { Reads all Names + Values of one Section } procedure TIniFile.ReadSectionValues(const section : string; strings : TStrings); var name : string; value : string; index : integer; begin strings.BeginUpdate; try strings.Clear; if FFileBuffer.Count > 0 then begin index := GetSectionIndex(section); if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do begin name := GetName(FFileBuffer[index]); if name <> '' then begin value := GetValue(FFileBuffer[index], name); strings.Add(name + separator + value); end; Inc(index); end; end; end; finally strings.EndUpdate; end; end; procedure TIniFile.ReadSectionRaw(const section : string; strings : TStrings); var eols,index : integer; begin strings.BeginUpdate; try eols:=0; strings.Clear; if FFileBuffer.Count > 0 then begin index := GetSectionIndex(section); if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do begin { Skip empty lines at the end of the section } if FFileBuffer[index]='' then inc(eols) else begin while eols>0 do begin Strings.Add(''); dec(eols); end; if not IsComment(FFileBuffer[index]) then strings.Add(FFileBuffer[index]); end; Inc(index); end; end; end; finally strings.EndUpdate; end; end; { Writes a String-Value for Ident in one Section. Note: If Section and/or Ident don't exist, they will be placed in the Ini-File } procedure TIniFile.WriteString(const section, ident, value : string); var index : integer; begin index := GetSectionIndex(section); { Section exists } if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) and (GetName(FFileBuffer[index]) <> ident) do Inc(index); if (index >= FFileBuffer.Count) or IsSection(FFileBuffer[index]) then begin { End of File or ident doesn't exists in the section } if ident <> '' then FFileBuffer.Insert(index, ident + separator + value); end else if ident <> '' then { Ident does exists in the section } FFileBuffer[index] := ident + separator + value; end else { section doesn't exists, so add new [section] with ident=value } begin FFileBuffer.Add(''); FFileBuffer.Add(brackets[0] + section + brackets[1]); if ident <> '' then FFileBuffer.Add(ident + separator + value); end; SaveToFile; end; { Writes an Integer-Value for Ident in one Section } procedure TIniFile.WriteInteger(const section, ident : string; value : longint); begin WriteString(section, ident, IntToStr(value)); end; { Writes a Bool-Value for Ident in one Section } procedure TIniFile.WriteBool(const section, ident : string; value : boolean); const values: array[boolean] of string = ('0', '1'); begin WriteString(section, ident, values[Value]); end; { Deletes the value of ident in one section. Note: Only if section and ident exist, the value of ident will be set to NULL } procedure TIniFile.DeleteKey(const section, ident : string); var index : integer; begin index := GetSectionIndex(section); if index <> -1 then begin Inc(index); while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) and (GetName(FFileBuffer[index]) <> ident) do Inc(index); if not (index >= FFileBuffer.Count) and not IsSection(FFileBuffer[index]) then begin { Ident does exists } FFileBuffer.Delete(index); SaveToFile; end; end; end; { Erases the whole Section from an Ini-File } procedure TIniFile.EraseSection(const section : string); var index : integer; begin index := GetSectionIndex(section); if index <> -1 then begin FFileBuffer.Delete(index); { Delete Section-Header } while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do FFileBuffer.Delete(index); { Delete Section-Items } if index > 0 then FFileBuffer.Insert(index, ''); SaveToFile; end; end; end. { $Log$ Revision 1.2 2000-09-01 21:37:30 peter * targetdir support (merged) Revision 1.1 2000/07/13 10:16:22 michael + Initial import Revision 1.1 2000/05/11 17:59:12 peter * makeini unit added as replacement for old inifiles unit }