Browse Source

Merged revision 30573 from http://svn.freepascal.org/svn/fpc/trunk
------------------------------------------------------------------------
r30573 | pierre | 2015-04-13 18:40:27 +0200 (Mon, 13 Apr 2015) | 1 line
Changed paths:
M /trunk/ide/wini.pas

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

git-svn-id: branches/fixes_3_0@31754 -

pierre 10 years ago
parent
commit
81a6f3ea2a
2 changed files with 114 additions and 42 deletions
  1. 8 8
      ide/fpini.pas
  2. 106 34
      ide/wini.pas

+ 8 - 8
ide/fpini.pas

@@ -612,7 +612,7 @@ begin
   { Files }
   { avoid keeping old files }
   INIFile^.DeleteSection(secFiles);
-  INIFile^.SetEntry(secFiles,ieOpenExts,'"'+OpenExts+'"');
+  INIFile^.SetEntry(secFiles,ieOpenExts,EscapeIniText(OpenExts));
   for I:=1 to High(RecentFiles) do
     begin
       if I<=RecentFileCount then
@@ -678,17 +678,17 @@ begin
   { Help }
   S:='';
   HelpFiles^.ForEach(@ConcatName);
-  INIFile^.SetEntry(secHelp,ieHelpFiles,'"'+S+'"');
+  INIFile^.SetEntry(secHelp,ieHelpFiles,EscapeIniText(S));
   { Editor }
   INIFile^.SetIntEntry(secEditor,ieDefaultTabSize,DefaultTabSize);
   INIFile^.SetIntEntry(secEditor,ieDefaultIndentSize,DefaultIndentSize);
   INIFile^.SetIntEntry(secEditor,ieDefaultEditorFlags,DefaultCodeEditorFlags);
   INIFile^.SetEntry(secEditor,ieDefaultSaveExt,DefaultSaveExt);
   { Highlight }
-  INIFile^.SetEntry(secHighlight,ieHighlightExts,'"'+HighlightExts+'"');
-  INIFile^.SetEntry(secHighlight,ieTabsPattern,'"'+TabsPattern+'"');
+  INIFile^.SetEntry(secHighlight,ieHighlightExts,EscapeIniText(HighlightExts));
+  INIFile^.SetEntry(secHighlight,ieTabsPattern,EscapeIniText(TabsPattern));
   { SourcePath }
-  INIFile^.SetEntry(secSourcePath,ieSourceList,'"'+SourceDirs+'"');
+  INIFile^.SetEntry(secSourcePath,ieSourceList,EscapeIniText(SourceDirs));
   { Mouse }
   INIFile^.SetIntEntry(secMouse,ieDoubleClickDelay,DoubleDelay);
   INIFile^.SetIntEntry(secMouse,ieReverseButtons,byte(MouseReverse));
@@ -718,9 +718,9 @@ begin
     begin
       S:=IntToStr(I);
       GetToolParams(I-1,S1,S2,S3,W);
-      if S1<>'' then S1:='"'+S1+'"';
-      if S2<>'' then S2:='"'+S2+'"';
-      if S3<>'' then S3:='"'+S3+'"';
+      if S1<>'' then S1:=EscapeIniText(S1);
+      if S2<>'' then S2:=EscapeIniText(S2);
+      if S3<>'' then S3:=EscapeIniText(S3);
       INIFile^.SetEntry(secTools,ieToolName+S,S1);
       INIFile^.SetEntry(secTools,ieToolProgram+S,S2);
       INIFile^.SetEntry(secTools,ieToolParams+S,S3);

+ 106 - 34
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;
@@ -83,11 +87,38 @@ const MainSectionName : string[40] = 'MainSection';
       CommentChar     : char = ';';
       ValidStrDelimiters: set of char = ['''','"'];
 
+function EscapeIniText(S : string) : String;
+
 implementation
 
 uses
   WUtils;
 
+function EscapeIniText(S : string) : String;
+var
+  delimiter : char;
+  i: integer;
+begin
+  delimiter:=#0;
+  while delimiter < #255 do
+    begin
+      if (delimiter in ValidStrDelimiters) and
+         (pos(delimiter,S)=0) then
+        break;
+      delimiter:=succ(delimiter);
+    end;
+  if delimiter=#255 then
+    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}
@@ -120,11 +151,18 @@ 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;
-    delimiter : char;
-    i : longint;
 begin
   if Text=nil then
     begin
@@ -135,26 +173,7 @@ begin
           begin
             { if Value contains CommentChar, we need to add delimiters }
             if pos(CommentChar,S)>0 then
-              begin
-                delimiter:=#0;
-                while delimiter < #255 do
-                  begin
-                    if (delimiter in ValidStrDelimiters) and
-                       (pos(delimiter,S)=0) then
-                      break;
-                    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));
-
-                s:=delimiter+s+delimiter;
-              end;
+              S:=EscapeIniText(S);
             S:=S+' '+CommentChar+' '+CoS;
           end
     end
@@ -192,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;
@@ -201,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;
@@ -219,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
@@ -280,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;
 
@@ -511,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
@@ -525,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