MG: using strings instead of TStrings

git-svn-id: trunk@1814 -
This commit is contained in:
lazarus 2002-08-02 09:43:33 +00:00
parent a78ba5c3c4
commit 9524a6acd9
2 changed files with 224 additions and 72 deletions

View File

@ -39,108 +39,260 @@ uses
type
TTextDiffFlag = (
tdfIgnoreSpaceCharAmount,
tdfIgnoreSpaceChars,
tdfIgnoreEmptyLineChanges,
tdfIgnoreCase
tdfIgnoreSpaceCharAmount, // ignore if space chars were added or removed
// except if all spaces were removed
tdfIgnoreSpaceChars, // ignore spaces (newline chars not included)
tdfIgnoreHeadingSpaces, // ignore spaces at start of line
tdfIgnoreTrailingSpaces, // ignore spaces at end of line
tdfIgnoreEmptyLineChanges,// ignore if empty lines were added or removed
tdfIgnoreLineEnds, // ignore if line chars differ (e.g. #10 = #13#10)
tdfIgnoreCase // ignore case of letters
);
TTextDiffFlags = set of TTextDiffFlag;
procedure CreateTextDiff(Text1, Text2, DiffText: TStrings;
Flags: TTextDiffFlags);
function CreateTextDiff(const Text1, Text2: string; Flags: TTextDiffFlags
): string;
implementation
var
IsSpaceChars: array[char] of boolean;
UpperCaseChars: array[char] of char;
const
IsSpaceChars, UpperCaseChars: array[char] of boolean;
function IsEmptyLine(const s: string; Flags: TTextDiffFlags): boolean;
var i: integer;
procedure GetLineExtends(const s: string; LineStart: integer;
var LineEnd, NextLineStart: integer);
var Len: integer;
begin
if ([tdfIgnoreSpaceCharAmount,tdfIgnoreSpaceChars]*Flags)<>[] then begin
Len:=length(s);
LineEnd:=LineStart;
while (LineEnd<=Len) do begin
if (not (s[LineEnd] in [#10,#13])) then begin
inc(LineEnd);
end else begin
NextLineStart:=LineEnd+1;
if (NextLineStart<=Len) and (s[NextLineStart] in [#10,#13])
and (s[LineStart]<>s[NextLineStart]) then
inc(NextLineStart);
exit;
end;
end;
// this was the last line and it has no line end
NextLineStart:=LineEnd;
end;
function IsEmptyLine(const s: string; LineStart, LineEnd: integer;
Flags: TTextDiffFlags): boolean;
var
i: integer;
begin
if ([tdfIgnoreSpaceCharAmount,tdfIgnoreSpaceChars,tdfIgnoreHeadingSpaces,
tdfIgnoreTrailingSpaces]*Flags)<>[] then
begin
Result:=true;
for i:=1 to length(s) do begin
for i:=LineStart to LineEnd-1 do begin
if not IsSpaceChars[s[i]] then begin
Result:=false;
exit;
end;
end;
end else begin
Result:=(s='');
Result:=(LineEnd=LineStart);
end;
end;
function LinesAreEqual(const Line1, Line2: string; Flags: TTextDiffFlags
): boolean;
var Pos1, Pos2, Len1, Len2: integer;
function LinesAreEqual(
const Text1: string; Line1Start, Line1End, NextLine1Start: integer;
const Text2: string; Line2Start, Line2End, NextLine2Start: integer;
Flags: TTextDiffFlags): boolean;
var
Start1, End1, Pos1,
Start2, End2, Pos2: integer;
begin
if ([tdfIgnoreSpaceCharAmount,tdfIgnoreSpaceChars]*Flags)<>[] then begin
// completely ignore space chars
Result:=true;
Len1:=length(Line1);
Len2:=length(Line2);
Pos1:=1;
Pos2:=1;
while (Pos1<=Len1) and (Pos2<=Len2) do begin
if ((not (tdfIgnoreCase in Flags))
and (Line1[Pos1]=Line2[Pos2]))
or ((tdfIgnoreCase in Flags)
and (UpperCaseChars[Line1[Pos1]]=UpperCaseChars[Line2[Pos2]]))
then begin
// both chars are the same
inc(Pos1);
inc(Pos2);
continue;
end else begin
// there is a difference
if (tdfIgnoreSpaceChars in Flags) then begin
if IsSpaceChars[Line1[Pos1]]
or IsSpaceChars[Line2[Pos2]]
then begin
// skip spaces
while (Pos1<=Len1) and IsSpaceChars[Line1[Pos1]] do inc(Pos1);
while (Pos2<=Len2) and IsSpaceChars[Line2[Pos2]] do inc(Pos2);
Start1:=Line1Start;
End1:=Line1End;
Start2:=Line2Start;
End2:=Line2End;
if [tdfIgnoreHeadingSpaces,tdfIgnoreSpaceChars]*Flags<>[] then begin
// ignore spaces at start of line
while (Start1<End1) and IsSpaceChars[Text1[Start1]] do inc(Start1);
while (Start2<End2) and IsSpaceChars[Text2[Start2]] do inc(Start2);
end;
if [tdfIgnoreTrailingSpaces,tdfIgnoreSpaceChars]*Flags<>[] then begin
// ignore spaces at end of line
while (Start1<End1) and IsSpaceChars[Text1[End1-1]] do dec(End1);
while (Start2<End2) and IsSpaceChars[Text2[End2-1]] do dec(End2);
end;
// compare line content (i.e. the chars without the line end)
Pos1:=Start1;
Pos2:=Start2;
while (Pos1<End1) and (Pos2<End2) do begin
if not IsSpaceChars[Text1[Pos1]] then begin
// Text1 contains a normal char
if not IsSpaceChars[Text1[Pos1]] then begin
// Text2 contains a normal char
if tdfIgnoreCase in Flags then begin
// compare case insensitive
if UpperCaseChars[Text1[Pos1]]=UpperCaseChars[Text2[Pos2]] then begin
// no diff -> proceed with next chars
inc(Pos1);
inc(Pos2);
end else begin
// diff found -> lines differ
Result:=false;
exit;
end;
end else begin
xxx
// compare case sensitive
if Text1[Pos1]=Text2[Pos2] then begin
// no diff -> proceed with next chars
inc(Pos1);
inc(Pos2);
end else begin
// diff found -> lines differ
Result:=false;
exit;
end;
end;
end else begin
// Text2 contains a space
if not (tdfIgnoreSpaceChars in Flags) then begin
// diff found -> lines differ
Result:=false;
exit;
end else begin
// skip all spaces in Text2 and proceed the search
repeat
inc(Pos2);
until (Pos2>=End2) or (IsSpaceChars[Text2[Pos2]]);
end;
end;
end else begin
// Text1 contains a space
if not IsSpaceChars[Text2[Pos2]] then begin
// Text2 contains a normal char
if not (tdfIgnoreSpaceChars in Flags) then begin
// diff found -> lines differ
Result:=false;
exit;
end else begin
// skip all spaces in Text1 and proceed the search
repeat
inc(Pos1);
until (Pos1>=End1) or (IsSpaceChars[Text1[Pos1]]);
end;
end else begin
// Text2 contains a space
if [tdfIgnoreSpaceChars,tdfIgnoreSpaceCharAmount]*Flags<>[] then begin
// skip all spaces in Text1 and Text2 and proceed the search
repeat
inc(Pos1);
until (Pos1>=End1) or (IsSpaceChars[Text1[Pos1]]);
repeat
inc(Pos2);
until (Pos2>=End2) or (IsSpaceChars[Text2[Pos2]]);
end else begin
// compare the space chars
if Text1[Pos1]=Text2[Pos2] then begin
// no diff -> proceed with next chars
inc(Pos1);
inc(Pos2);
end else begin
// diff found -> lines differ
Result:=false;
exit;
end;
end;
end;
end;
end else begin
if (tdfIgnoreCase in Flags) then begin
Result:=(AnsiCompareText(Line1,Line2)=0);
end else begin
Result:=(AnsiCompareStr(Line1,Line2)=0);
end;
if (Pos1<End1) or (Pos2<End2) then begin
// one line is longer -> lines differ
Result:=false;
exit;
end;
// compare line ends
if not (tdfIgnoreLineEnds in Flags) then begin
Pos1:=Line1End;
Pos2:=Line2End;
while (Pos1<NextLine1Start) and (Pos2<NextLine2Start)
and (Text1[Pos1]=Text2[Pos2]) do begin
inc(Pos1);
inc(Pos2);
end;
Result:=(Pos1=NextLine1Start) and (Pos2=NextLine2Start);
end else begin
Result:=true;
end;
end;
procedure CreateTextDiff(Text1, Text2, DiffText: TStrings;
Flags: TTextDiffFlags);
var Cnt1, Cnt2, Line1, Line2: integer;
function CreateTextDiff(const Text1, Text2: string; Flags: TTextDiffFlags
): string;
var
LineNumber1, LineNumber2: integer;
Len1, Line1Start, Line1End, NextLine1Start: integer;
Len2, Line2Start, Line2End, NextLine2Start: integer;
DiffMemStream: TMemoryStream;
begin
DiffText.Clear;
Cnt1:=Text1.Count;
Cnt2:=Text2.Count;
Line1:=1;
Line2:=1;
// read empty lines
if (tdfIgnoreEmptyLineChanges in Flags) then begin
while (Line1<Cnt1) and (IsEmptyLine(Text1[Line1],Flags)) do
inc(Line1);
while (Line2<Cnt2) and (IsEmptyLine(Text2[Line2],Flags)) do
inc(Line2);
end;
// read lines that are equal
while (Line1<Cnt1) and (Line2<Cnt2)
and LinesAreEqual(Text1[Line1],Text2[Line2],Flags) do begin
inc(Line1);
inc(Line2);
DiffMemStream:=TMemoryStream.Create;
try
Len1:=length(Text1);
Len2:=length(Text2);
LineNumber1:=1;
LineNumber2:=1;
Line1Start:=1;
Line2Start:=1;
// search for a differing line ...
repeat
// skip empty lines in Text1 and get line1 extends ...
while (Line1Start<=Len1) do begin
GetLineExtends(Text1,Line1Start,Line1End,NextLine1Start);
if not (tdfIgnoreEmptyLineChanges in Flags)
or not IsEmptyLine(Text1,Line1Start,Line1End,Flags) then
break;
Line1Start:=NextLine1Start;
inc(LineNumber1);
end;
// skip empty lines in Text2 and get line2 extends ...
while (Line2Start<=Len2) do begin
GetLineExtends(Text2,Line2Start,Line2End,NextLine2Start);
if not (tdfIgnoreEmptyLineChanges in Flags)
or not IsEmptyLine(Text2,Line2Start,Line2End,Flags) then
break;
Line2Start:=NextLine2Start;
inc(LineNumber2);
end;
// skip equal lines ...
if (Line1Start<=Len1) and (Line2Start<=Len2) then begin
if not LinesAreEqual(Text1,Line1Start,Line1End,NextLine1Start,
Text2,Line2Start,Line2End,NextLine2Start,
Flags)
then
break;
Line1Start:=NextLine1Start;
inc(LineNumber1);
Line2Start:=NextLine2Start;
inc(LineNumber2);
end else begin
// one text is longer than the other
// ToDo:
//AddDiff(Text1,Text2,Line1Start,Len1,Line2Start,Len2);
exit;
end;
until false;
// differing line found -> search next equal line
// ToDo:
finally
SetLength(Result,DiffMemStream.Size);
DiffMemStream.Position:=0;
if Result<>'' then
DiffMemStream.Read(Result[1],length(Result));
DiffMemStream.Free;
end;
end;
@ -148,7 +300,7 @@ procedure InternalInit;
var c: char;
begin
for c:=Low(char) to High(char) do begin
IsSpaceChars[c]:=c in [' ',#9,#10,#13];
IsSpaceChars[c]:=c in [' ',#9];
UpperCaseChars[c]:=upcase(c);
end;
end;

View File

@ -34,7 +34,7 @@ interface
uses
Classes, SysUtils, IDEProcs, Forms, Controls, Buttons, ExtCtrls, StdCtrls,
LResources, Project, SynEdit, LCLType;
LResources, Project, SynEdit, LCLType, DiffPatch;
type
TDiskDiffsDlg = class(TForm)