home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sp15demo.zip / libsrc.zip / LIBSRC / INIFILES.PAS < prev    next >
Pascal/Delphi Source File  |  1996-01-28  |  15KB  |  584 lines

  1. unit IniFiles; { IniFiles for SpeedPascal 1.5 }
  2.  
  3. { TIniFile: Standard (binäres) OS/2 Inifile
  4.   TAsciiIniFile: Text-Inifile, lesbar, mit Editor zu bearbeiten.
  5.  
  6.   Beide benutzen exakt das gleiche Interface und sind bis
  7.   auf die neue Methode 'Erase' kompatibel zu den normalen
  8.   Delphi-Inifiles. }
  9.  
  10. interface
  11.  
  12. uses Lists, PMSHL; { OS/2 profile functions }
  13.  
  14. type
  15.   EIniFileError = class(Exception);
  16.  
  17. type
  18.   TIniFile = class(TObject)
  19.   private
  20.     FFileName: PString;         // Physical name of file
  21.     FHandle: HINI;              // Profile handle
  22.     function GetFileName: string;
  23.  
  24.   protected
  25.     procedure Error(const Msg: string); virtual;
  26.  
  27.   public
  28.     constructor Create(const FileName: string);
  29.     destructor Destroy; override;
  30.     procedure Erase(const Section, Ident: string); virtual;
  31.     procedure EraseSection(const Section: string); virtual;
  32.     function ReadString(const Section, Ident, Default: string): string; virtual;
  33.     function ReadInteger(const Section, Ident: string; Default: Longint): Longint; virtual;
  34.     function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; virtual;
  35.     procedure ReadSection(const Section: string; AStrings: TStrings); virtual;
  36.     procedure ReadSectionValues(const Section: string; AStrings: TStrings); virtual;
  37.     procedure WriteString(const Section, Ident, Value: String); virtual;
  38.     procedure WriteInteger(const Section, Ident: string; Value: Longint); virtual;
  39.     procedure WriteBool(const Section, Ident: string; Value: Boolean); virtual;
  40.  
  41.     property FileName: string
  42.       read GetFileName;
  43.   end;
  44.  
  45. type
  46.   TAsciiIniFile = class(TIniFile)
  47.   private
  48.     //FFileName: PString;         // Physical name of file
  49.     FSections: TStringList;     // List of sections and their names
  50.     FName: PString;             // Name of last used section
  51.     FList: TStringList;         // List of last used section
  52.     FChanged: Boolean;          // Has the data been changed?
  53.     procedure WriteToSection(const Section: string);
  54.     function ReadFromSection(const Section: string): Boolean;
  55.     //function GetFileName: string;
  56.  
  57.   protected
  58.     FTrueString: string[7];
  59.     FFalseString: string[7];
  60.  
  61.   public
  62.     constructor Create(const FileName: string);
  63.     destructor Destroy; override;
  64.     procedure Erase(const Section, Ident: string); override;
  65.     procedure EraseSection(const Section: string); override;
  66.     function ReadString(const Section, Ident, Default: string): string; override;
  67.     function ReadInteger(const Section, Ident: string; Default: Longint): Longint; override;
  68.     function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; override;
  69.     procedure ReadSection(const Section: string; AStrings: TStrings); override;
  70.     procedure ReadSectionValues(const Section: string; AStrings: TStrings); override;
  71.     procedure Refresh;
  72.     procedure WriteString(const Section, Ident, Value: String); override;
  73.     procedure WriteInteger(const Section, Ident: string; Value: Longint); override;
  74.     procedure WriteBool(const Section, Ident: string; Value: Boolean); override;
  75.  
  76.     property FileName: string
  77.       read GetFileName;
  78.     property Changed: Boolean
  79.       read FChanged write FChanged;
  80.   end;
  81.  
  82. function GetDefaultINI: string;
  83.   { Get name of INI-file that matches program path & name with
  84.     extension .INI instead of .EXE }
  85.  
  86. implementation
  87.  
  88. uses
  89.   SysUtils;
  90.  
  91. const
  92.   NULL = 0;
  93.  
  94. type
  95.   TIniSection = class(TStringList)
  96.     function GetValue(const Name: string): string; override;
  97.     procedure SetValue(const Name, Value: string); override;
  98.     function FindValue(const Name: string; var Value: string): LongInt; override;
  99.     {function Get(Index: LongInt): string; override;
  100.     procedure Put(Index: LongInt; const S: string); override;}
  101.     procedure Delete(Index: LongInt); override;
  102.   end;
  103.  
  104. function CutStr(var S: string; C: Char): string;
  105. var
  106.   P: Integer;
  107. begin
  108.   P := Pos(C, S);
  109.   if P = 0 then
  110.   begin
  111.     Result := S;
  112.     SetLength(S, 0);
  113.   end
  114.   else
  115.   begin
  116.     Result := Copy(S, 1, P - 1);
  117.     Delete(S, 1, P);
  118.   end;
  119. end;
  120.  
  121. function TrimStr(const S: string): string;
  122. var
  123.   L, R: Integer;
  124. begin
  125.   R := Length(S);
  126.   while (R > 0) and (S[R] = ' ') do Dec(R);
  127.   L := 1;
  128.   while (L <= R) and (S[L] = ' ') do Inc(L);
  129.   Result := Copy(S, L, R - L + 1);
  130. end;
  131.  
  132. function GetDefaultINI: string;
  133. begin
  134.   Result := ExpandFileName(ChangeFileExt(ParamStr(0), '.INI'));
  135. end;
  136.  
  137. { TIniSection }
  138.  
  139. procedure TIniSection.Delete(Index: LongInt);
  140. var
  141.   P: PString;
  142. begin
  143.   P := PString(GetObject(Index));
  144.   DisposeStr(P);
  145.   inherited Delete(Index);
  146. end;
  147.  
  148. {procedure TIniSection.Put(Index: LongInt; const S: string);
  149. var
  150.   Ident, Value: string;
  151. begin
  152.   Value := S;
  153.   Ident := CutStr(Value, '=');
  154.   SetValue(Ident, Value);
  155. end;}
  156.  
  157. function TIniSection.GetValue(const Name: string): string;
  158. var
  159.   I: LongInt;
  160. begin
  161.   if Find(Name, I) then Result := PString(GetObject(I))^
  162.   else Result := '';
  163. end;
  164.  
  165. function TIniSection.FindValue(const Name: string; var Value: string): LongInt;
  166. begin
  167.   if Find(Name, Result) then Value := PString(GetObject(Result))^
  168.   else
  169.   begin
  170.     Value := '';
  171.     Result := -1;
  172.   end;
  173. end;
  174.  
  175. procedure TIniSection.SetValue(const Name, Value: string);
  176. var
  177.   I: LongInt;
  178.   P: PString;
  179. begin
  180.   if Find(Name, I) then
  181.   begin
  182.     P := PString(GetObject(I));
  183.     DisposeStr(P);
  184.     PutObject(I, TObject(NewStr(Value)));
  185.   end
  186.   else
  187.   begin
  188.     Sorted := False;
  189.     InsertObject(I, Name, TObject(NewStr(Value)));
  190.     Sorted := True;
  191.   end;
  192. end;
  193.  
  194. { TIniFile }
  195.  
  196. constructor TIniFile.Create(const FileName: string);
  197. begin
  198.   FHandle := PrfOpenProfile(AppHandle, FileName);
  199.   if FHandle = NULL then Error('Cannot open ini-file.');
  200.   FFileName := NewStr(FileName);
  201. end;
  202.  
  203. destructor TIniFile.Destroy;
  204. begin
  205.   PrfCloseProfile(FHandle);
  206.   DisposeStr(FFileName);
  207. end;
  208.  
  209. procedure TIniFile.Erase(const Section, Ident: string);
  210. begin
  211.   PrfWriteProfileString(FHandle, Section, Ident, nil);
  212. end;
  213.  
  214. procedure TIniFile.EraseSection(const Section: string);
  215. begin
  216.   PrfWriteProfileString(FHandle, Section, nil, nil);
  217. end;
  218.  
  219. procedure TIniFile.Error(const Msg: string);
  220. begin
  221.   raise EIniFileError.Create(Msg);
  222. end;
  223.  
  224. function TIniFile.GetFileName: string;
  225. begin
  226.   Result := FFileName^;
  227. end;
  228.  
  229. function TIniFile.ReadString(const Section, Ident, Default: string): string;
  230. var
  231.   CSection, CIdent, CDefault: CString[256];
  232. begin
  233.   CSection := Section;
  234.   CIdent := Ident;
  235.   CDefault := Default;
  236.   SetLength(Result, PrfQueryProfileString(FHandle,
  237.     CSection, CIdent, CDefault, Result[1], 255) - 1);
  238. end;
  239.  
  240. function TIniFile.ReadInteger(const Section, Ident: string; Default: Longint): Longint;
  241. begin
  242.   Result := PrfQueryProfileInt(FHandle, Section, Ident, Default);
  243. end;
  244.  
  245. function TIniFile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
  246. var
  247.   L: LongInt;
  248. begin
  249.   if Default then L := 1 else L := 0;
  250.   Result := (PrfQueryProfileInt(FHandle, Section, Ident, L) <> 0);
  251. end;
  252.  
  253. procedure TIniFile.ReadSection(const Section: string; AStrings: TStrings);
  254. var
  255.   Size, RealSize: LongInt;
  256.   Buffer, Pos: PChar;
  257.   S: string;
  258. begin
  259.   if not PrfQueryProfileSize(FHandle, Section, nil, Size) then Exit;
  260.   GetMem(Buffer, Size);
  261.   try
  262.     PrfQueryProfileString(FHandle, Section, nil, nil, Buffer, Size);
  263.     Buffer[Size - 1] := #0;
  264.     Pos := Buffer;
  265.     while Pos[0] <> #0 do
  266.     begin
  267.       S := StrPas(Pos);
  268.       Inc(Pos, Length(S) + 1);
  269.       Dec(RealSize, Length(S) + 1);
  270.       AStrings.Add(S);
  271.     end;
  272.   finally
  273.     FreeMem(Buffer, Size);
  274.   end;
  275. end;
  276.  
  277. procedure TIniFile.ReadSectionValues(const Section: string; AStrings: TStrings);
  278. var
  279.   Temp: TIniSection;
  280.   I: LongInt;
  281. begin
  282.   Temp := TIniSection.Create;
  283.   Temp.Sorted := True;
  284.   Temp.Duplicates := dupIgnore;
  285.   try
  286.     ReadSection(Section, Temp);
  287.     for I := 0 to Temp.Count - 1 do
  288.       AStrings.SetValue(Temp.Get(I),
  289.         ReadString(Section, Temp.Get(I), ''));
  290.   finally
  291.     Temp.Destroy;
  292.   end;
  293. end;
  294.  
  295. procedure TIniFile.WriteString(const Section, Ident, Value: String);
  296. var
  297.   CSection, CIdent, CValue: CString[256];
  298. begin
  299.   CSection := Section;
  300.   CIdent := Ident;
  301.   CValue := Value;
  302.   if not PrfWriteProfileString(FHandle, CSection, CIdent, CValue) then
  303.     Error('Error during write.');
  304. end;
  305.  
  306. procedure TIniFile.WriteInteger(const Section, Ident: string; Value: Longint);
  307. begin
  308.   WriteString(Section, Ident, IntToStr(Value));
  309. end;
  310.  
  311. procedure TIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
  312. var
  313.   C: Char;
  314. begin
  315.   if Value then C := '1' else C := '0';
  316.   WriteString(Section, Ident, C);
  317. end;
  318.  
  319. { TAsciiIniFile }
  320.  
  321. constructor TAsciiIniFile.Create(const FileName: string);
  322. var
  323.   Source: Text;
  324.   S, T: string;
  325. begin
  326.   FSections := TStringList.Create;
  327.   FSections.Duplicates := dupIgnore;
  328.   FSections.Sorted := True;
  329.   FTrueString := 'True';
  330.   FFalseString := 'False';
  331.  
  332.   FFileName := NewStr(FileName);
  333.   FName := NullStr;
  334.  
  335.   if FFileName <> NullStr then
  336.   begin
  337.     Assign(Source, FileName);
  338.     {$i-}
  339.     Reset(Source);
  340.     {$i+}
  341.     if IOResult = 0 then
  342.     begin
  343.       while not EOF(Source) do
  344.       begin
  345.         ReadLn(Source, S);
  346.         if Length(S) <> 0 then
  347.         begin
  348.           if S[1] = '[' then
  349.           begin
  350.             { New Section }
  351.             Delete(S, 1, 1);
  352.             WriteToSection(CutStr(S, ']'));
  353.           end
  354.           else
  355.           if not (S[1] in [';', '#', '%']) then
  356.           begin
  357.             { New entry }
  358.             if FList = nil then WriteToSection('');
  359.             T := CutStr(S, '=');
  360.             FList.AddObject(TrimStr(T), TObject(NewStr(TrimStr(S))));
  361.           end;
  362.         end;
  363.       end;
  364.       Close(Source);
  365.     end;
  366.   end;
  367. end;
  368.  
  369. destructor TAsciiIniFile.Destroy;
  370. var
  371.   I: LongInt;
  372. begin
  373.   Refresh;
  374.   DisposeStr(FName);
  375.   DisposeStr(FFileName);
  376.   for I := 0 to FSections.Count - 1 do
  377.   begin
  378.     FList := FSections.GetObject(I);
  379.     FList.Destroy;
  380.   end;
  381.   FSections.Destroy;
  382. end;
  383.  
  384. procedure TAsciiIniFile.Erase(const Section, Ident: string);
  385. var
  386.   I: LongInt;
  387. begin
  388.   if ReadFromSection(Section) then
  389.   begin
  390.     if FList.Find(Ident, I) then FList.Delete(I);
  391.   end;
  392. end;
  393.  
  394. procedure TAsciiIniFile.EraseSection(const Section: string);
  395. var
  396.   I: LongInt;
  397.   S: TIniSection;
  398. begin
  399.   if FSections.Find(Section, I) then
  400.   begin
  401.     S := FSections.GetObject(I);
  402.     S.Destroy;
  403.     FSections.Delete(I);
  404.     if S = FList then
  405.     begin
  406.       AssignStr(FName, '');
  407.       FList := nil;
  408.     end;
  409.     FChanged := True;
  410.   end;
  411. end;
  412.  
  413. procedure TAsciiINIFile.WriteToSection(const Section: string);
  414. var
  415.   I: LongInt;
  416. begin
  417.   if CompareText(Section, FName^) <> 0 then
  418.   begin
  419.     if FSections.Find(Section, I) then
  420.     begin
  421.       AssignStr(FName, Section);
  422.       FList := FSections.GetObject(I);
  423.     end
  424.     else
  425.     begin
  426.       FList := TIniSection.Create;
  427.       FList.Duplicates := dupAccept;
  428.       FList.Sorted := True;
  429.       FList.CaseSensitive := False;
  430.       FSections.AddObject(Section, FList);
  431.       AssignStr(FName, Section);
  432.     end;
  433.   end;
  434. end;
  435.  
  436. function TAsciiINIFile.ReadFromSection(const Section: string): Boolean;
  437. var
  438.   I: LongInt;
  439. begin
  440.   if CompareText(Section, FName^) <> 0 then
  441.   begin
  442.     if FSections.Find(Section, I) then
  443.     begin
  444.       AssignStr(FName, Section);
  445.       FList := FSections.GetObject(I);
  446.     end;
  447.   end;
  448.   Result := (FList <> nil);
  449. end;
  450.  
  451. {function TAsciiIniFile.GetFileName: string;
  452. begin
  453.   Result := FFileName^;
  454. end;}
  455.  
  456. function TAsciiIniFile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
  457. var
  458.   S: string;
  459. begin
  460.   if ReadFromSection(Section) then
  461.   with TIniSection(FList) { as TIniSection} do
  462.   begin
  463.     if FindValue(Ident, S) = -1 then Result := Default
  464.     else
  465.     begin
  466.       if CompareText(S, FTrueString) = 0 then Result := True
  467.       else if CompareText(S, FFalseString) = 0 then Result := False
  468.       else Result := Default;
  469.     end;
  470.   end
  471.   else Result := Default;
  472. end;
  473.  
  474. function TAsciiIniFile.ReadInteger(const Section, Ident: string; Default: Longint): Longint;
  475. var
  476.   S: string;
  477. begin
  478.   if ReadFromSection(Section) then
  479.   with TIniSection(FList) { as TIniSection} do
  480.   begin
  481.     if FindValue(Ident, S) = -1 then Result := Default
  482.     else Result := StrToIntDef(S, Default);
  483.   end
  484.   else Result := Default;
  485. end;
  486.  
  487. function TAsciiIniFile.ReadString(const Section, Ident, Default: string): string;
  488. begin
  489.   if ReadFromSection(Section) then
  490.   with TIniSection(FList) { as TIniSection} do
  491.   begin
  492.     if FindValue(Ident, Result) = -1 then Result := Default;
  493.   end
  494.   else Result := Default;
  495. end;
  496.  
  497. procedure TAsciiIniFile.ReadSection(const Section: string; AStrings: TStrings);
  498. var
  499.   N: LongInt;
  500. begin
  501.   if ReadFromSection(Section) then
  502.   begin
  503.     for N := 0 to FList.Count - 1 do AStrings.Add(FList.Get(N));
  504.   end;
  505. end;
  506.  
  507. procedure TAsciiIniFile.ReadSectionValues(const Section: string; AStrings: TStrings);
  508. var
  509.   N: LongInt;
  510. begin
  511.   if ReadFromSection(Section) then
  512.   begin
  513.     for N := 0 to FList.Count - 1 do
  514.       AStrings.Add(FList.Get(N) + '=' + PString(FList.GetObject(N))^);
  515.   end;
  516. end;
  517.  
  518. procedure TAsciiIniFile.Refresh;
  519. var
  520.   Dest: Text;
  521.   N, I: LongInt;
  522.   L: TStringList;
  523.   S: string;
  524. begin
  525.   if FChanged and (FFileName <> NullStr) then
  526.   begin
  527.     Assign(Dest, FileName);
  528.     Rewrite(Dest);
  529.     for N := 0 to FSections.Count - 1 do
  530.     begin
  531.       S := FSections.Get(N);
  532.       if Length(S) <> 0 then
  533.       begin
  534.         WriteLn(Dest, '[' + S + ']');
  535.         WriteLn(Dest);
  536.       end;
  537.       L := FSections.GetObject(N);
  538.       for I := 0 to L.Count - 1 do
  539.         WriteLn(Dest, L.Get(I), '=', PString(L.GetObject(I))^);
  540.       if N < FSections.Count then WriteLn(Dest);
  541.       FChanged := False;
  542.     end;
  543.     Close(Dest);
  544.   end;
  545. end;
  546.  
  547. procedure TAsciiIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
  548. begin
  549.   FChanged := True;
  550.   WriteToSection(Section);
  551.   if Value then FList.SetValue(Ident, FTrueString)
  552.   else FList.SetValue(Ident, FFalseString);
  553. end;
  554.  
  555. procedure TAsciiIniFile.WriteInteger(const Section, Ident: string; Value: LongInt);
  556. begin
  557.   FChanged := True;
  558.   WriteToSection(Section);
  559.   FList.SetValue(Ident, IntToStr(Value));
  560. end;
  561.  
  562. procedure TAsciiIniFile.WriteString(const Section, Ident, Value: string);
  563. begin
  564.   FChanged := True;
  565.   WriteToSection(Section);
  566.   FList.SetValue(Ident, Value);
  567. end;
  568.  
  569. end.
  570.  
  571. { Änderungen: 26.11.95  Sections werden sortiert, Einträge aber nicht
  572.               28.11.95  Alles wird sortiert, schneller durch Trennung
  573.                         von Ident und Value (TIniSection).
  574.               30.11.95  Fehler in TIniSection korrigiert, es
  575.                         fehlten Get/Put
  576.               16.12.95  Neue Funktion GetDefaultINI()
  577.  
  578.   To-Do: - Eventuell ReadData / WriteData einbauen
  579.          - Eventuell ReadSectionNames einbauen
  580.          - Wenn String -> CString Fehler in SP/2 behoben,
  581.            Workaround entfernen.
  582.  
  583.  
  584.