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