Ver código fonte

Use pascal style doubling of quote char instead of C style escaping for ini file

git-svn-id: trunk@30573 -
pierre 10 anos atrás
pai
commit
54621aec9a
1 arquivos alterados com 95 adições e 28 exclusões
  1. 95 28
      ide/wini.pas

+ 95 - 28
ide/wini.pas

@@ -23,11 +23,13 @@ type
     PINIEntry = ^TINIEntry;
     TINIEntry = object(TObject)
       constructor Init(const ALine: string);
+      constructor Init(const ATag,AValue,AComment: string);
       function    GetText: string;
       function    GetTag: string;
       function    GetComment: string;
       function    GetValue: string;
       procedure   SetValue(const S: string);
+      procedure   SetComment(const S: string);
       destructor  Done; virtual;
     private
       TagHash  : Cardinal;
@@ -44,6 +46,7 @@ type
       constructor Init(const AName: string);
       function    GetName: string;
       function    AddEntry(const S: string): PINIEntry;
+      function    AddEntry(const Tag,Value,Comment: string): PINIEntry;
       function    SearchEntry(Tag: string): PINIEntry; virtual;
       procedure   DeleteEntry(Tag: string);
       procedure   ForEachEntry(EnumProc: pointer); virtual;
@@ -68,6 +71,7 @@ type
       procedure   ForEachEntry(const Section: string; EnumProc: pointer); virtual;
       function    GetEntry(const Section, Tag, Default: string): string; virtual;
       procedure   SetEntry(const Section, Tag, Value: string); virtual;
+      procedure   SetEntry(const Section, Tag, Value,Comment: string); virtual;
       function    GetIntEntry(const Section, Tag: string; Default: longint): longint; virtual;
       procedure   SetIntEntry(const Section, Tag: string; Value: longint); virtual;
       procedure   DeleteSection(const Section: string); virtual;
@@ -90,15 +94,6 @@ implementation
 uses
   WUtils;
 
-{$IFOPT Q+}
-  {$Q-}
-  {$DEFINE REENABLE_Q}
-{$ENDIF}
-{$IFOPT R+}
-  {$R-}
-  {$DEFINE REENABLE_R}
-{$ENDIF}
-
 function EscapeIniText(S : string) : String;
 var
   delimiter : char;
@@ -113,16 +108,26 @@ begin
       delimiter:=succ(delimiter);
     end;
   if delimiter=#255 then
-    delimiter:='"';
-  { we use \", but we also need to escape \ itself }
-  for i:=length(s) downto 1 do
-    if (s[i]=delimiter) then
-      s:=copy(s,1,i-1)+'\'+delimiter+copy(s,i+1,length(s))
-    else if (s[i]='\') then
-      s:=copy(s,1,i-1)+'\\'+copy(s,i+1,length(s));
+    begin
+      { we use " delimiter, but the text also contains double quotes,
+        which need to be escaped, by doubling it }
+      delimiter:='"';
+      for i:=length(s) downto 1 do
+        if (s[i]=delimiter) then
+          s:=copy(s,1,i-1)+delimiter+copy(s,i+1,length(s));
+    end;
   EscapeIniText:=delimiter+s+delimiter;
 end;
 
+{$IFOPT Q+}
+  {$Q-}
+  {$DEFINE REENABLE_Q}
+{$ENDIF}
+{$IFOPT R+}
+  {$R-}
+  {$DEFINE REENABLE_R}
+{$ENDIF}
+
 function CalcHash(const s: String): Cardinal;
 var
   i: integer;
@@ -146,6 +151,15 @@ begin
   Split;
 end;
 
+constructor TINIEntry.Init(const ATag,AValue,AComment: string);
+begin
+  inherited Init;
+  Tag:=NewStr(ATag);
+  Value:=NewStr(AValue);
+  Comment:=NewStr(AComment);
+  Text:=NewStr(GetText);
+end;
+
 
 function TINIEntry.GetText: string;
 var S,CoS: string;
@@ -197,6 +211,17 @@ begin
   end;
 end;
 
+procedure TINIEntry.SetComment(const S: string);
+begin
+  if (GetComment<>S) then
+  begin
+    if Text<>nil then DisposeStr(Text); Text:=nil;
+    if Comment<>nil then DisposeStr(Comment);
+    Comment:=NewStr(S);
+    Modified:=true;
+  end;
+end;
+
 
 procedure TINIEntry.Split;
 var S,ValueS: string;
@@ -206,7 +231,8 @@ var S,ValueS: string;
     InString: boolean;
     Delimiter: char;
 begin
-  S:=GetText; Delimiter:=#0;
+  S:=GetText;
+  Delimiter:=#0;
   P:=Pos('=',S); P2:=Pos(CommentChar,S);
   if (P2<>0) and (P2<P) then
     P:=0;
@@ -224,15 +250,14 @@ begin
               Delimiter:=C;
               InString:=true;
             end
-          { if Value is delimited with ' or ", handle escaping }
-          else if (Delimiter<>#0) and (C='\') and (P2<length(S)) then
+          else if (C=Delimiter) then
             begin
-              inc(P2);
-              C:=S[P2];
-              ValueS:=ValueS+C;
+              { Delimiter inside escaped Value are simply doubled }
+              if (P2+1<length(S)) and (S[P2+1]=Delimiter) then
+                ValueS:=ValueS+Delimiter
+              else
+                InString:=not InString;
             end
-          else if C=Delimiter then
-            InString:=not InString
           else if (C=CommentChar) and (InString=false) then
             Break
           else
@@ -285,10 +310,47 @@ begin
 end;
 
 function TINISection.AddEntry(const S: string): PINIEntry;
+var
+  E: PINIEntry;
+  Tag : String;
+begin
+  if pos('=',S)>0 then
+    begin
+      Tag:=copy(S,1,pos('=',S)-1);
+      E:=SearchEntry(Tag);
+    end
+  else
+    E:=nil;
+  if not assigned(E) then
+    begin
+      New(E, Init(S));
+      Entries^.Insert(E);
+    end
+  else
+    begin
+      if assigned(E^.Text) then
+         DisposeStr(E^.Text);
+      E^.Text:=NewStr(S);
+      E^.Split;
+    end;
+  AddEntry:=E;
+end;
+
+function TINISection.AddEntry(const Tag,Value,Comment: string): PINIEntry;
 var E: PINIEntry;
 begin
-  New(E, Init(S));
-  Entries^.Insert(E);
+  E:=SearchEntry(Tag);
+  if not assigned(E) then
+    begin
+      New(E, Init(Tag,Value,Comment));
+      Entries^.Insert(E);
+    end
+  else
+    begin
+      E^.SetValue(Value);
+      if Comment<>'' then
+        E^.SetComment(Comment);
+    end;
   AddEntry:=E;
 end;
 
@@ -516,7 +578,7 @@ begin
   GetEntry:=S;
 end;
 
-procedure TINIFile.SetEntry(const Section, Tag, Value: string);
+procedure TINIFile.SetEntry(const Section, Tag, Value,Comment: string);
 var E: PINIEntry;
     P: PINISection;
 begin
@@ -530,13 +592,18 @@ begin
           New(P, Init(Section));
           Sections^.Insert(P);
         end;
-      E:=P^.AddEntry(Tag+'='+Value);
+      E:=P^.AddEntry(Tag,Value,Comment);
       E^.Modified:=true;
     end;
   if E<>nil then
     E^.SetValue(Value);
 end;
 
+procedure TINIFile.SetEntry(const Section, Tag, Value: string);
+begin
+  SetEntry(Section,Tag,Value,'');
+end;
+
 function TINIFile.GetIntEntry(const Section, Tag: string; Default: longint): longint;
 var L: longint;
 begin