1 {
2 ���������������������������������������������������������������������������Ŀ
3 �                                                                           �
4 �      ��۰ ۰  ۰ ��۰   ��۰ ��۰ ۰   ��۰   ۰ ۰ ۰  ۰ ��۰ ��۰      �
5 �       ۰  �۰ ۰  ۰    ۰    ۰  ۰   ۰     ۰ ۰ �۰ ۰  ۰   ۰       �
6 �       ۰  ۰۰۰  ۰    �۰   ۰  ۰   �۰    ۰ ۰ ۰۰۰  ۰   ۰       �
7 �       ۰  ۰ �۰  ۰    ۰    ۰  ۰   ۰     ۰ ۰ ۰ �۰  ۰   ۰       �
8 �      ��۰ ۰  ۰ ��۰   ۰   ��۰ ��۰ ��۰   ���۰ ۰  ۰ ��۰  ۰       �
9 �                                                                           �
10 �      Ver. : 1.00b ...... (c) 1996 by Stephan Zehrer ...... FreeWare       �
11 �                                                                           �
12 ���������������������������������������������������������������������������Ĵ
13 � IniFile Unit dient zur verarbeitung von config Dateien in Textform wie    �
14 � INI oder CFG.                                                             �
15 � Hier einige Features von IniFile Unit :                                   �
16 �   - Einfache Bedinung (4 Routinen fuer Grund Funktionen)                  �
17 �   - Alles in einem Object, daduch mehrer Listen gleichzeitig nutzbar      �
18 �   - Aufleilung in Untergruppen (Sectionen)                                �
19 �   - Kommentarverwaltung von jede Option (';')                             �
20 �   - kommplette Einlesen der Ini File in eine einfach verkettete Liste     �
21 �   - schnelle Verarbeitung da keine lese/schreib zugriffe Waeren des       �
22 �     ein und auslesens.                                                    �
23 �   - DataBase Funktionen                                                   �
24 �     ( Aufbau von kleine Datenbanken in Textform wie z.B. PLZ Listen oder  �
25 �       Listen von Telefon Nummern )                                        �
26 �                                                                           �
27 �     !!! Achtung Version ohne externe Functionen (siehe Dateiende) !!!     �
28 �                                                                           �
29 ���������������������������������������������������������������������������Ĵ
30 � Diese Version wurde ausgibig von mir getestet. Es kann trotzdem vorkommen �
31 � das sich Fehler einschleichen.                                            �
32 � Bitte schicken Sie einen Bug report an : Stephan Zehrer@2:2487/9001.14    �
33 �                                                                           �
34 � Der Autor uebernimmt keine Haftung fuer Schaeden, die durch dieses Programm�
35 � entstanden sind.                                                          �
36 �����������������������������������������������������������������������������
37 
38 changed by Sascha Silbe
39 }
40 {$X+}{$R-}{ $L-}{ $D-}{$Y-}{$X+}{$G+}
41 unit IniFile;
42 
43 interface
44 
45 uses DOS;
46 
47 type FileStr    = {String [12]} String[128]; {Externer Typ}
48      pOptRec = ^tOptRec;
49      tOptRec = record               {Record fuer die Optionen}
50                  Name    : String[20]; {Name, wenn ';' dann nur Kommentarzeile}
51 {$IfDef MKNL}
52                  Value   : String; {Wert}
53 {$Else}
54                  Value   : String[80]; {Wert}
55 {$EndIf}
56                  Comment : String[100]; {Kommentar}
57                  PrevOpt : pOptRec; {Zeiger auf vorherige Option}
58                  NextOpt : pOptRec; {Zeiger auf naechste Option}
59                end;
60      pSecRec = ^tSecRec;
61      tSecRec = record               {Record fuer die Sectionen}
62                  Name : String[20]; {Name der Secion, immer grossbustaben}
63                  Options : pOptRec; {Zeiger auf die Optionen}
64                  PrevSec : pSecRec; {Zeiger auf vorherige Section}
65                  NextSec : pSecRec; {Zeiger auf naechste Section}
66                end;
67 
68 type IniObj = object
69                 FileName   : FileStr;
70                 Sep        : Char;    {default = '='}
71                                       {Achtung aenderungen werden nicht
72                                        in der ini Datei gespeichert}
73                 CommentPos : byte;    {Wenn 0 dann deaktiviert, sonnst
74                                        position an der die Kommentare
75                                        ausgerichtet werden, natuerlich nur
76                                        wenn der normal Eintrag nicht laenger
77                                        ist. default = 0}
78                 NotFound   : String[20];  {String der zurueckgegeben wird wenn
79                                        ein eintrag nicht gefunden wurde
80                                        default = ''}
81                 f          : Text;
82                 IniTree    : pSecRec;  {Zeiger auf die 1. Section}
83                 AktSec     : pSecRec;  {nur intern benutzt}
84                 AktOpt     : pOptRec;  {nur intern benutzt}
85                 constructor Init (AFileName : FileStr);
86                 { Initalisiert die Ini Datei }
87                 destructor Done;
88                 { Schreibt die Eintraege und loeschen den Verkettung }
89                 procedure SetSeperator (ASep : Char);
90                 { Aendert den Seperator, default (=) }
91                 procedure SetNotFound  (ANotFound : String);
92                 { Aendert den NoFound String, default () }
93                 procedure SetCommentPos (ACommentPos : byte);
94                 { Aendert die CommentPos, default (0) }
ReadEntrynull95                 function ReadEntry ( Section : String;
96                                      Option  : String ) : String;
97                 { Liefert den Wert des Eintrags }
98                 procedure WriteEntry ( Section : String;
99                                        Option  : String;
100                                        Value   : String;
101                                        Comment : String);
102                 { Aendert/ Definiert eine Eintrag }
103                 procedure AddEntry ( Section : String;
104                                      Option  : String;
105                                      Value   : String;
106                                      Comment : String);
107                 { Fuegt einen Eintrag ans Ende der Section an }
108                 procedure InsertEntry ( Section : String;
109                                         Option  : String;
110                                         Value   : String;
111                                         Comment : String);
112                 { Fuegt einen Eintrag an der aktuellen Position ein }
113                 procedure DelEntry ( Section : String;
114                                      Option  : String;
115                                      DelSec  : Boolean );
116                 { Loescht eine Eintrag }
117                 { --------- Datenbank Routinen -------- }
118                 { Mit den Datenbank Functionen ist es moeglich
119                   auch Eintraege zu Lesen deren Options Name
120                   man nicht kennt. Wie kleine Datenbanken, wie
121                   z.B. eine kleine Liste von PLZ und ihren Ortnamen
122                   oder Telefonnummern ...
123                   Die Functionen sind Sections orientiert geschrieben,
124                   es ist dadurch moeglich Eine Datenbank und Programm
125                   Einstellungen zu kombinieren.
126                   Die Daten werden nicht Sortiert, neue Eintraege werden
127                   einfach hinten angehaengt.}
128                 procedure SetSection (Section : String);
129                 { Setzt die Interen Variabel AktSec, existierd die Section
130                   nicht wird eine neu Section erstellet.
131                   Setzt AktOpt auf den ersten gueltigen Eintrag
132                   ( wenn es einen gibt !!) }
133                 { DIESE PROCEDURE SOLLT ALS ERSTES AUFGREUFEN WERDEN}
134                 procedure ReSetSec;
135                 { Setzt AktOpt wirde auf den 1 Wert. }
GetSecNumnull136                 function GetSecNum (Section : String ) : integer;
137                 { gibt die Anzahl der Eintraegein einer Section }
138                 { dabei werden Kommentarzeilen ingnoriert. }
139                 { zurueck. Wenn Rueckgabewert 0 ist dann ist entweder kein }
140                 { Eintrag vorhanden oder die Section existiert nicht.}
SetNextOptnull141                 function SetNextOpt : boolean;
142                 { Setzt AktSec auf die naechste Option und gibt false
143                   zurueck falls wenn das ende Erreicht ist.
144                   Kommentarzeilen werden uebergangen}
SetPrevOptnull145                 function SetPrevOpt : boolean;
146                 { Setzt AktSec auf die vorherige Option und gibt false
147                   zurueck falls wenn der Anfang Erreicht ist.
148                   Kommentarzeilen werden uebergangen}
ReSecEnNamenull149                 function ReSecEnName  : String;
150                 { Was so viel heisst wie ReadSectionEntryName }
151                 { gibt den Namen der Aktuellen Option zurueck }
152                 { Ist AktOpt = NIL wird der NotFound String zurueck gegeben }
ReSecEnValuenull153                 function ReSecEnValue : String;
154                 { gibt den Wert der Aktuellen Option zurueck }
155                 { Ist AktOpt = NIL wird der NotFound String zurueck gegeben }
SearchSecEntrynull156                 function SearchSecEntry (Name : String ) : String;
157                 { Sucht nach einen Eintrag und gibt seine Wert zurueck. }
158                 { AktOpt wird nicht geaendert !! }
159                 procedure WriteSecEntry (Name    : String;
160                                          Value   : String;
161                                          Comment : String);
162                 { Schreibz den Eintrag neu oder aendert den Wert, der
163                   Aktuellen Section
164                   AktOpt wird nicht geaendert !!
165                   Achtung !! wurde keine Section gesetzt wird der Eintrag
166                   in eine falsche oder in keine Section geschrieben !!}
167                 procedure AddSecEntry (Name    : String;
168                                        Value   : String;
169                                        Comment : String);
170                 { Haengt einen neuen Eintrag hinten an, der Aktuellen Section
171                   AktOpt wird nicht geaendert !!
172                   Achtung !! wurde keine Section gesetzt wird der Eintrag
173                   in eine falsche oder in keine Section geschrieben !!}
174                 procedure InsertSecEntry (Name    : String;
175                                           Value   : String;
176                                           Comment : String);
177                 { Fuegt einen neuen Eintrag ein, der Aktuellen Section
178                   AktOpt wird nicht geaendert !!
179                   Achtung !! wurde keine Section gesetzt wird der Eintrag
180                   in eine falsche oder in keine Section geschrieben !!}
181                 procedure DelSecEntry (Name : String);
182                 { Loescht eine Eintrag in der Aktuellen Section
183                   AktOpt wird nicht geaendert !!
184                   Achtung !! wurde keine Section gesetzt wird kein oder
185                   ein falscher Eintrag geloescht }
186                 procedure DelCurEntry (DelSec  : Boolean);
187                 { Loescht eine Eintrag in der Aktuellen Section
188                   AktOpt wird nicht geaendert !!
189                   Achtung !! wurde keine Section gesetzt wird kein oder
190                   ein falscher Eintrag geloescht }
191                 { ---------- interen Routinen --------- }
SearchSectionnull192                 function SearchSection (ASection : String;
193                                         Last : Boolean ) : boolean;
SearchOptionnull194                 function SearchOption  (AOption : String;
195                                         Last : Boolean ) : boolean;
196                 procedure ReadIni;
197                 procedure WriteIni;
198                 procedure DelIni;
199                 procedure ShowTree;
200               end;
201 
202 implementation
203 {****************************** externe Routinen ****************************}
204 { Die hier externen Routinen stammen aus meiner Toolbox welche ich aus alle
205   moeglichen Quellen zusammen gestellt habe. Hier die Routinen die fuer
206   IniFile Unit noetig sind. Quellen : PRUSSG,SWAG,TOOLBOX,DOS,FIDO...        }
207 
208 {Function FileExists(FileName: string; attr : Word) : Boolean;
209 var f: SearchRec;
210 begin
211   findfirst(Filename, attr, f);
212   if doserror = 0 then Fileexists := true else Fileexists := false;
213 end;}
214 
FillStrnull215 Function FillStr (AStr : String; Len : byte; Ch : Char) : String;
216 begin
217   if Length (AStr) > Len then Exit;
218   while Length (AStr) < Len do AStr := AStr + Ch;
219   FillStr := AStr;
220 end;
StrCutnull221 Function StrCut (AStr : String) : String;
222 begin
223   while (Length(AStr) - 1 >= 0) AND
224         (AStr [Length(AStr)] in [#32,#9]) DO
225     AStr[0] := chr(Length(AStr) - 1);
226   StrCut := AStr;
227 end;
CutStrnull228 Function CutStr (AStr : String) : String;
229 begin
230   while (Length(AStr) - 1 >= 0) AND
231         (AStr [1] in [#32,#9]) DO
232     AStr := Copy (AStr,2,Length(AStr) - 1);
233   CutStr := AStr;
234 end;
235 
UpStrnull236 Function UpStr(S1:String) : String;
237 {Asm Code replaced by Sascha Silbe}
238 Var
239   s:String;
240   i:Byte;
241 
242 Begin
243 s[0]:= S1[0];
244 For i:= 1 to Byte(s1[0]) do s[i]:= UpCase(s1[i]);
245 UpStr:= s;
246 End;
247 
KillSpcsnull248 Function KillSpcs(s: String): String; {kill leading and trailing spaces}
249  Begin
250  While (s[1] in [' ', #9]) and (Length(s) > 0) do Delete(s, 1, 1);
251  While (s[Length(s)] in [' ', #9]) and (Length(s) > 0) do Delete(s, Length(s), 1);
252  KillSpcs := s;
253  End;
254 
255 
256 {****************************** externe Routinen ****************************}
NewSecnull257 function NewSec : pSecRec;
258 var ASec : pSecRec;
259 begin
260   New (ASec);
261   ASec^.Name := '';
262   ASec^.Options := NIL;
263   ASec^.PrevSec := NIL;
264   ASec^.NextSec := NIL;
265   NewSec := ASec;
266 end;
NewOptnull267 function NewOpt : pOptRec;
268 var AOpt : pOptRec;
269 begin
270   New (AOpt);
271   AOpt^.Name := '';
272   AOpt^.Value := '';
273   AOpt^.Comment := '';
274   AOpt^.PrevOpt := NIL;
275   AOpt^.NextOpt := NIL;
276   NewOpt := AOpt;
277 end;
278 {****************************************************************************}
279 constructor IniObj.Init(AFileName: FileStr);
280 begin
281   FileName := AFileName;
282   Assign (f,FileName);
283   Sep := '=';
284   NotFound := '';
285   CommentPos := 0;
286   IniTree := NIL;
287   AktSec := NIL;
288   AktOpt := NIL;
289   ReadIni;
290 end;
291 destructor IniObj.Done;
292 begin
293   WriteIni;
294   DelIni;
295 end;
296 {****************************************************************************}
297 
298 procedure IniObj.SetSeperator(ASep : Char);
299 begin
300   Sep := ASep;
301 end;
302 procedure IniObj.SetNotFound(ANotFound: String);
303 begin
304   NotFound := ANotFound;
305 end;
306 procedure   IniObj.SetCommentPos(ACommentPos: Byte);
307 begin
308   CommentPos := ACommentPos;
309 end;
310 {****************************************************************************}
311 
312 procedure IniObj.ReadIni;
313 var ASec : pSecRec;
314     AOpt : pOptRec;
315     X,Y  : byte;
316     Str  : String;
317 begin
318  {$I-} Reset (F); {$I+}
319  If IOResult <> 0 then
320    Begin
321 {    WriteLn('ReadIni: Couldn''t open file!');}
322    Exit;
323    end;
324  while not Eof(F) do
325   Begin
326   ReadLn (f,Str);
327   While (Str[Length(Str)] in [#13, #10]) do Dec(Str[0]);
328   KillSpcs(Str);
329   if Length (Str) > 0 then
330    begin
331    if Str[1] = '[' then
332     begin
333     ASec := NewSec;
334     X := Pos (']',Str);
335     if X > 1 then Dec (X,2) else Dec(x, 1);
336     ASec^.Name := UpStr(KillSpcs(Copy (Str,2,X)));
337     if IniTree = NIL then IniTree := ASec;
338     if AktSec <> NIL then
339      Begin
340      AktSec^.NextSec := ASec;
341      ASec^.PrevSec := AktSec;
342      End;
343     AktSec := ASec;
344     end
345    else
346     begin
347     X := Pos (Sep,Str); Y := Pos (' ;',Str);
348     If (Str[1] = ';') then Y := 1;
349     if (Y > 0) or (X > 0) then
350      begin
351      AOpt := NewOpt;
352      if Str[1] = ';' then
353       begin
354       AOpt^.Name := ';'; {Kommentarzeile}
355       AOpt^.Comment := Copy (Str,2,Length(Str)-1);
356       end
357      else
358       begin
359       If (x = 0) then
360        begin
361        AOpt^.Name := KillSpcs(Copy (Str, 1, y-1));
362        AOpt^.Value := '';
363        AOpt^.Comment := KillSpcs(Copy(Str, y+1, Length(str)-y));
364        end
365       else
366        begin
367        AOpt^.Name := KillSpcs(Copy (Str,1,X-1));
368        if Y <> 0 then
369         begin
370         AOpt^.Value := KillSpcs(Copy (Str,X+1,Y-X-1));
371         AOpt^.Comment := KillSpcs(Copy (Str,Y+1,Length(Str)-Y));
372         end
373        else
374         begin
375         AOpt^.Value := KillSpcs(Copy (Str,X+1,Length(Str)-X));
376         AOpt^.Comment := '';
377         end;
378        end;
379       end;
380      end
381     else
382      begin
383      AOpt^.Name := KillSpcs(Str);
384      AOpt^.Value := '';
385      AOpt^.Comment := '';
386      end;
387     if IniTree = NIL then
388      begin
389      IniTree := NewSec;
390      AktSec := IniTree;
391      end;
392     if AktSec^.Options = NIL then AktSec^.Options := AOpt
393     else AktOpt^.NextOpt := AOpt;
394     AOpt^.PrevOpt := AktOpt;
395     AktOpt := AOpt;
396     end;
397    end;
398   end;
399  Close (f);
400 end;
401 procedure IniObj.WriteIni;
402 const Comment : String = '';
403       OptVal  : String = '';
404 begin
405   if IniTree = Nil then Exit;
406 {  FileMode := 2;}
407   {$I-} Rewrite (f); {$I+}
408   If IOResult <> 0 then
409     Begin
410 {    WriteLn('WriteIni: Couldn''t open file!');}
411     Exit;
412     End;
413   AktSec := IniTree;
414   AktOpt := AktSec^.Options;
415   {$I-}
416   while AktSec <> NIL do begin
417     if AktSec^.Name <> '' then WriteLn (f,'['+UpStr(AktSec^.Name)+']');
418     while AktOpt <> NIL do begin
419       if AktOpt^.Name = ';' then WriteLn (f,AktOpt^.Name+AktOpt^.Comment)
420       else begin
421         OptVal :=  AktOpt^.Name+'='+ AktOpt^.Value;
422         if AktOpt^.Comment <> '' then begin
423           if CommentPos <> 0 then OptVal := FillStr (OptVal,CommentPos,' ');
424           Comment := '  ;'+AktOpt^.Comment
425         end;
426         WriteLn (f, OptVal + Comment);
427         Comment := ''; OptVal := '';
428       end;
429       AktOpt := AktOpt^.NextOpt;
430     end;
431     AktSec := AktSec^.NextSec;
432     If AktSec <> Nil then AktOpt := AktSec^.Options;
433   end;
434   If IOResult <> 0 then
435     Begin
436 {    WriteLn('WriteIni: Couldn''t write file!');}
437     End;
438 
439   Close (f); {$I-}
440   If IOResult <> 0 then
441     Begin
442 {    WriteLn('WriteIni: Couldn''t close file!');}
443     End;
444 end;
445 procedure IniObj.DelIni;
446 var ASec : pSecRec;
447     AOpt : pOptRec;
448     X    : byte;
449     Str  : String;
450 begin
451   if IniTree = Nil then Exit;
452   AktSec := IniTree;
453   AktOpt := AktSec^.Options;
454   while AktSec <> NIL do begin
455     ASec := AktSec^.NextSec;
456     if AktSec <> NIl then Dispose (AktSec);
457     while AktOpt <> NIL do begin
458       AOpt := AktOpt^.NextOpt;
459       if AktOpt <> NIL then Dispose (AktOpt);
460       AktOpt := AOpt;
461     end;
462     AktSec := ASec;
463     If AktSec <> Nil then AktOpt := AktSec^.Options;
464   end;
465 end;
466 {****************************************************************************}
IniObj.SearchSectionnull467 function IniObj.SearchSection (ASection : String;
468                                Last     : boolean ) : boolean;
469 { Suchen nach der Section. Ist Last auf true wird AktSec auf die Section
470   vor der gesuchten gesetzt, ist Last auf false wird AktSec auf die
471   gesuchte Section gesetzt, oder bei nicht finden auf die letzte der
472   Verkettung. Wird eine Section gefunde ist der Rueckgabewert der Function
473   true, ansonsten false.
474   Zur beschleunigung der Suche : ist AktSec schon das gesuchte wird nicht
475   gesucht, wie z.B. durch WriteSecEntry }
476 var Found : boolean;
477     ASec  : pSecRec;
478 begin
479   if IniTree = Nil then begin
480     SearchSection := false;
481     Exit;
482   end;
483   found := false;
484   ASection := UpStr (ASection);
485   ASec := NIL;
486   If AktSec = NIL then AktSec := IniTree
487   Else
488     if (AktSec^.Name = ASection) and (not Last) then Found := true
489     else AktSec := IniTree;
490   while (AktSec <> NIL) and (not Found) do begin
491     if ASection = AktSec^.Name then Found := true
492     Else
493      begin
494       ASec := AktSec;
495       AktSec := AktSec^.NextSec;
496      end;
497   end;
498   if Last or (AktSec = NIL) then AktSec := ASec;
499   SearchSection := found;
500 end;
IniObj.SearchOptionnull501 function IniObj.SearchOption (AOption : String;
502                               Last    : boolean) : boolean;
503 { Suchen nach der Option. Ist Last auf true wird AktOpt auf die Option
504   vor der gesuchten gesetzt, ist Last auf false wird AktOpt auf die
505   gesuchte Option gesetzt, oder bei nicht finden auf die letzte der
506   Verkettung, Nur wenn gar keine Verkettung unter dieser Section
507   existiert wird AktOpt auf NIL gesetzt. Aber dann ist auch der
508   rueckgabewert der Function false
509   Zur beschleunigung der Suche : ist AktOpt schon das gesuchte wird nicht
510   gesucht}
511 
512 var Found : boolean;
513     AOpt  : pOptRec;
514 begin
515   if IniTree = Nil then begin
516     SearchOption := false;
517     Exit;
518   end;
519   found := false;
520   AOpt := NIL;
521   if (UpStr(AktOpt^.Name) = UpStr(AOption)) and (not Last) then Found := true
522   else AktOpt := AktSec^.Options;
523   while (AktOpt <> NIL) and (not Found) do begin
524     if UpStr(AOption) = UpStr(AktOpt^.Name) then Found := true;
525     if not Found then begin
526       AOpt :=  AktOpt;
527       AktOpt := AktOpt^.NextOpt;
528     end;
529   end;
530   If Last or (AktOpt = NIL) then AktOpt := AOpt;
531   SearchOption := found;
532 end;
533 {****************************************************************************}
IniObj.ReadEntrynull534 function IniObj.ReadEntry ( Section : String; Option  : String ) : String;
535 Var Value : String;
536 begin
537   if SearchSection (Section,false) then
538     if SearchOption (Option,false) then
539      Value := AktOpt^.Value
540     else Value := NotFound;
541   ReadEntry := Value;
542 end;
543 procedure IniObj.WriteEntry(Section, Option, Value, Comment: String);
544 begin
545   if SearchSection (Section,false) then
546     if SearchOption (Option,false) then
547      begin
548        AktOpt^.Value := Value;
549        if Comment <> '' then AktOpt^.Comment := Comment;
550      end else
551      begin
552        AktOpt^.NextOpt := NewOpt;
553        AktOpt := AktOpt^.NextOpt;
554        AktOpt^.Name := Option;
555        AktOpt^.Value := Value;
556        AktOpt^.Comment := Comment;
557      end
558   else begin
559     if IniTree = NIL then begin
560       IniTree := NewSec;
561       AktSec := IniTree;
562     end else begin
563       AktSec^.NextSec := NewSec;
564       AktSec := AktSec^.NextSec;
565     end;
566     AktSec^.Name := UpStr(Section);
567     AktSec^.Options := NewOpt;
568     AktOpt := AktSec^.Options;
569     AktOpt^.Name := Option;
570     AktOpt^.Value := Value;
571     AktOpt^.Comment := Comment;
572   end;
573 end;
574 procedure IniObj.AddEntry(Section, Option, Value, Comment: String);
575 Var
576   AOpt : pOptRec;
577 begin
578   if SearchSection (Section,false) then
579      begin
580        AOpt := AktOpt;
581        While (AOpt^.NextOpt <> Nil) do AOpt := AOpt^.NextOpt;
582        AOpt^.NextOpt := NewOpt;
583        AOpt^.PrevOpt := AktOpt;
584        AOpt := AOpt^.NextOpt;
585        AOpt^.Name := Option;
586        AOpt^.Value := Value;
587        AOpt^.Comment := Comment;
588      end
589   else begin
590     if IniTree = NIL then begin
591       IniTree := NewSec;
592       AktSec := IniTree;
593     end else begin
594       AktSec^.NextSec := NewSec;
595       AktSec^.NextSec^.PrevSec := AktSec;
596       AktSec := AktSec^.NextSec;
597     end;
598     AktSec^.Name := UpStr(Section);
599     AktSec^.Options := NewOpt;
600     AktOpt := AktSec^.Options;
601     AktOpt^.Name := Option;
602     AktOpt^.Value := Value;
603     AktOpt^.Comment := Comment;
604   end;
605 end;
606 procedure IniObj.InsertEntry(Section, Option, Value, Comment: String);
607 Var
608   AOpt : pOptRec;
609 begin
610   if SearchSection (Section,false) then
611      begin
612        AOpt := AktOpt^.NextOpt;
613        AktOpt^.NextOpt := NewOpt;
614        AktOpt^.NextOpt^.PrevOpt := AktOpt;
615        AktOpt^.NextOpt^.NextOpt := AOpt;
616        AOpt := AktOpt^.NextOpt;
617        AOpt^.Name := Option;
618        AOpt^.Value := Value;
619        AOpt^.Comment := Comment;
620      end
621   else begin
622     if IniTree = NIL then begin
623       IniTree := NewSec;
624       AktSec := IniTree;
625     end else begin
626       AktSec^.NextSec := NewSec;
627       AktSec^.NextSec^.PrevSec := AktSec;
628       AktSec := AktSec^.NextSec;
629     end;
630     AktSec^.Name := UpStr(Section);
631     AktSec^.Options := NewOpt;
632     AktOpt := AktSec^.Options;
633     AktOpt^.Name := Option;
634     AktOpt^.Value := Value;
635     AktOpt^.Comment := Comment;
636   end;
637 end;
638 procedure IniObj.DelEntry ( Section : String;
639                             Option  : String;
640                             DelSec  : Boolean );
641 var AOpt : pOptRec;
642     ASec : pSecRec;
643 begin
644   if SearchSection (Section,false) then
645     if SearchOption (Option,false) then begin
646       AOpt := AktOpt;
647       SearchOption (Option,true);
648       if AktOpt <> NIL then
649         Begin
650         AktOpt^.NextOpt := AOpt^.NextOpt;
651         AOpt^.NextOpt^.PrevOpt := AktOpt;
652         End
653       else
654         Begin
655         AktSec^.Options := AOpt^.NextOpt;
656         AOpt^.NextOpt^.PrevOpt := Nil;
657         End;
658       if AOpt <> NIL then Dispose (AOpt);
659       if (AktSec^.Options = NIL) and DelSec then begin
660         ASec := AktSec;
661         SearchSection (Section,true);
662         if AktSec <> NIL then
663           Begin
664           AktSec^.NextSec := ASec^.NextSec;
665           ASec^.NextSec^.PrevSec := AktSec;
666           End
667         else
668           Begin
669           IniTree := ASec^.NextSec;
670           ASec^.NextSec^.PrevSec := Nil;
671           End;
672         if ASec <> NIL then Dispose (ASec);
673       end;
674     end;
675 end;
676 {****************************************************************************}
677 procedure IniObj.ShowTree;
678 const Comment : String = '';
679       OptVal  : String = '';
680 begin
681   if IniTree = Nil then Exit;
682   AktSec := IniTree;
683   AktOpt := AktSec^.Options;
684   while AktSec <> NIL do begin
685     if AktSec^.Name <> '' then WriteLn ('['+AktSec^.Name+']');
686     while AktOpt <> NIL do begin
687       if AktOpt^.Name = ';' then WriteLn (AktOpt^.Name+AktOpt^.Comment)
688       else begin
689         OptVal :=  AktOpt^.Name+'='+ AktOpt^.Value;
690         if AktOpt^.Comment <> '' then begin
691           if CommentPos <> 0 then OptVal := FillStr (OptVal,CommentPos,' ');
692           Comment := '  ;'+AktOpt^.Comment
693         end;
694         WriteLn (OptVal + Comment);
695         Comment := ''; OptVal := '';
696       end;
697       AktOpt := AktOpt^.NextOpt;
698     end;
699     AktSec := AktSec^.NextSec;
700     If (AktSec <> Nil) then AktOpt := AktSec^.Options;
701   end;
702 end;
703 
704 {****************************************************************************}
IniObj.SetPrevOptnull705 function IniObj.SetPrevOpt : boolean;
706 
707 begin
708   if AktOpt^.PrevOpt <> Nil then begin
709     repeat AktOpt := AktOpt^.PrevOpt
710     until (AktOpt^.Name <> ';') or (AktOpt^.PrevOpt = Nil);
711     if (AktOpt^.PrevOpt = Nil) and ( AktOpt^.Name = ';')
712      then SetPrevOpt := false else SetPrevOpt := true;
713   end else SetPrevOpt := false;
714 end;
IniObj.SetNextOptnull715 function IniObj.SetNextOpt : boolean;
716 
717 begin
718   if AktOpt^.NextOpt <> Nil then begin
719     repeat AktOpt := AktOpt^.NextOpt
720     until (AktOpt^.Name <> ';') or (AktOpt^.NextOpt = Nil);
721     if (AktOpt^.NextOpt = Nil) and ( AktOpt^.Name = ';')
722      then SetNextOpt := false else SetNextOpt := true;
723   end else SetNextOpt := false;
724 end;
IniObj.GetSecNumnull725 function IniObj.GetSecNum (Section : String ) : integer;
726 var Num  : Integer;
727     AOpt : pOptRec;
728 begin
729   Num := 0;
730   AOpt := AktOpt;
731   if SearchSection (Section,false) then begin
732     AktOpt := AktSec^.Options;
733     while AktOpt <> NIL do begin
734       if AktOpt^.Name[1] <> ';' then Inc (Num);
735       if not SetNextOpt then AktOpt := NIL;
736     end;
737   end;
738   AktOpt := AOpt;
739   GetSecNum := Num;
740 end;
741 procedure IniObj.SetSection (Section : String);
742 begin
743   if not SearchSection (Section,false) then begin
744     WriteEntry (Section,';','','');
745   end;
746   ReSetSec;
747 end;
748 procedure IniObj.ReSetSec;
749 begin
750   AktOpt := AktSec^.Options;
751   if AktOpt^.Name = ';' then SetNextOpt;
752 end;
IniObj.ReSecEnNamenull753 function IniObj.ReSecEnName  : String;
754 begin
755   if AktOpt = NIL then begin
756     ReSecEnName := NotFound;
757     Exit;
758   end;
759   ReSecEnName := AktOpt^.Name;
760 end;
761 
IniObj.ReSecEnValuenull762 function IniObj.ReSecEnValue : String;
763 begin
764   if AktOpt = NIL then begin
765     ReSecEnValue := NotFound;
766     Exit;
767   end;
768   ReSecEnValue := AktOpt^.Value;
769 end;
IniObj.SearchSecEntrynull770 function  IniObj.SearchSecEntry (Name : String ) : String;
771 var AOpt : pOptRec;
772 begin
773   if AktSec = NIL then begin
774     SearchSecEntry := NotFound;
775     Exit;
776   end;
777   AOpt := AktOpt;
778   SearchSecEntry := ReadEntry (AktSec^.Name,Name);
779   AktOpt := AOpt;
780 end;
781 procedure IniObj.WriteSecEntry (Name    : String;
782                                 Value   : String;
783                                 Comment : String);
784 var AOpt : pOptRec;
785 begin
786   if AktSec = NIL then Exit;
787   AOpt := AktOpt;
788   WriteEntry (AktSec^.Name,Name,Value,'');
789   AktOpt := AOpt;
790 end;
791 procedure IniObj.AddSecEntry (Name    : String;
792                               Value   : String;
793                               Comment : String);
794 var AOpt : pOptRec;
795 begin
796   if AktSec = NIL then Exit;
797   AOpt := AktOpt;
798   AddEntry (AktSec^.Name,Name,Value,'');
799   AktOpt := AOpt;
800 end;
801 procedure IniObj.InsertSecEntry (Name    : String;
802                                  Value   : String;
803                                  Comment : String);
804 var AOpt : pOptRec;
805 begin
806   if AktSec = NIL then Exit;
807   AOpt := AktOpt;
808   InsertEntry (AktSec^.Name,Name,Value,'');
809   AktOpt := AOpt;
810 end;
811 procedure IniObj.DelSecEntry (Name  : String);
812 var AOpt : pOptRec;
813 begin
814   if AktSec = NIL then Exit;
815   AOpt := AktOpt;
816   DelEntry (AktSec^.Name,Name,false);
817   AktOpt := AOpt;
818 end;
819 procedure IniObj.DelCurEntry(DelSec: Boolean);
820 var AOpt : pOptRec;
821     ASec : pSecRec;
822 begin
823 If (AktOpt = Nil) then Exit
824 Else If (AktOpt = AktSec^.Options) Then
825   Begin
826   AktSec^.Options := AktOpt^.NextOpt;
827   AktOpt^.NextOpt^.PrevOpt := Nil;
828   End
829 Else If (AktOpt^.NextOpt = Nil) then
830   Begin
831   AktOpt^.PrevOpt^.NextOpt := Nil;
832   End
833 Else
834   Begin
835   AktOpt^.PrevOpt^.NextOpt := AktOpt^.NextOpt;
836   AktOpt^.NextOpt^.PrevOpt := AktOpt^.PrevOpt;
837   End;
838 Dispose(AktOpt);
839 if (AktSec^.Options = NIL) and DelSec then
840   Begin
841   If (AktSec^.PrevSec = Nil) then
842     Begin
843     If (AktSec^.NextSec <> Nil) then
844       Begin
845       AktSec^.NextSec^.PrevSec := Nil;
846       IniTree := AktSec^.NextSec;
847       End
848     Else IniTree := Nil;
849     End
850   Else
851     Begin
852     AktSec^.PrevSec^.NextSec := AktSec^.NextSec;
853     AktSec^.NextSec^.PrevSec := AktSec^.PrevSec;
854     End;
855   Dispose(AktSec);
856   End;
857 end;
858 
859 {****************************************************************************}
860 end.
861 { Externale Prceduren,Functionen & Typen
862   FileStr (T) : String Type fuer Dateiname. (String[12])
863   UpStr   (F) : wandelt alle Buchstaben in Grossbuchstaben.
864   CutStr  (F) : Schneidet vorstehende Leerzeichen und Tabs ab.
865   StrCut  (F) : Schneidet nachstehende Leerzeichen und Tabs ab.
866   FillStr (F) : Fuellt eine String mit eine Zeichen auf eine bestimmte Laenge
867   FileExists (F) : Prueft ob eine Datei Existiert (siehe Online Hilfe) mit
868                    Attribut ueberpruefung
869 }
870 {05.04.96 : Begin mit der Grundstruktur, Aufbau eines Objectes, Bug Fixes
871  06.04.96 : BugFixes, Implementierung Comments,SetCommentPos,NotFound,
872             DelEntry, ausgiebiger Test der Unit
873  07.04.96 : DataBase Routinen (Tested)
874 
875 Sascha Silbe:
876  12.07.98 : fixed some bugs
877 }
878