mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-07 22:47:59 +02:00
Remake AdjustLineBreaks.
This version is correct and supposedly better in other ways (except for a bit of clarity maybe).
This commit is contained in:
parent
8ecdc6ed05
commit
1c4151d82e
@ -783,69 +783,60 @@ end;
|
||||
|
||||
function AdjustLineBreaks(const S: string; Style: TTextLineBreakStyle): string;
|
||||
var
|
||||
Source,Dest: PAnsiChar;
|
||||
DestLen: Integer;
|
||||
I,J,L: Longint;
|
||||
|
||||
Sp,Se,SLiteralStart,SLiteralEnd,Rp: PChar;
|
||||
begin
|
||||
Source:=Pointer(S);
|
||||
L:=Length(S);
|
||||
DestLen:=L;
|
||||
I:=1;
|
||||
while (I<=L) do
|
||||
begin
|
||||
case S[i] of
|
||||
#10: if (Style=tlbsCRLF) then
|
||||
Inc(DestLen);
|
||||
#13: if (Style=tlbsCRLF) then
|
||||
if (I<L) and (S[i+1]=#10) then
|
||||
Inc(I)
|
||||
else
|
||||
Inc(DestLen)
|
||||
else if (I<L) and (S[I+1]=#10) then
|
||||
Dec(DestLen);
|
||||
end;
|
||||
Inc(I);
|
||||
end;
|
||||
if (DestLen=L) then
|
||||
Result:=S
|
||||
else
|
||||
begin
|
||||
SetLength(Result, DestLen);
|
||||
FillChar(Result[1],DestLen,0);
|
||||
Dest := Pointer(Result);
|
||||
J:=0;
|
||||
I:=0;
|
||||
While I<L do
|
||||
case Source[I] of
|
||||
#10: begin
|
||||
if Style=tlbsCRLF then
|
||||
begin
|
||||
Dest[j]:=#13;
|
||||
Inc(J);
|
||||
end;
|
||||
Dest[J] := #10;
|
||||
Inc(J);
|
||||
Inc(I);
|
||||
end;
|
||||
#13: begin
|
||||
if Style=tlbsCRLF then
|
||||
begin
|
||||
Dest[j] := #13;
|
||||
Inc(J);
|
||||
end;
|
||||
Dest[j]:=#10;
|
||||
Inc(J);
|
||||
Inc(I);
|
||||
if Source[I]=#10 then
|
||||
Inc(I);
|
||||
end;
|
||||
else
|
||||
Dest[j]:=Source[i];
|
||||
Inc(J);
|
||||
Inc(I);
|
||||
end;
|
||||
end;
|
||||
Result:='';
|
||||
repeat { Does two iterations, first is prepass, second fills the result with data and is distinguished by Assigned(Pointer(Result)). }
|
||||
Rp:=Pointer(Result);
|
||||
Sp:=PChar(S); { Readable #0 for empty string. }
|
||||
Se:=Sp+Length(S);
|
||||
SLiteralStart:=Sp;
|
||||
repeat
|
||||
while (Sp<Se) and not (Sp^ in [#13,#10]) do
|
||||
Inc(Sp);
|
||||
SLiteralEnd:=Sp; { Save position before consuming line ending. }
|
||||
if Sp^=#10 then { These accesses rely on terminating #0. }
|
||||
begin
|
||||
Inc(Sp);
|
||||
if Style=tlbsLF then
|
||||
continue;
|
||||
end
|
||||
else if Sp^=#13 then
|
||||
if Sp[1]=#10 then
|
||||
begin
|
||||
Inc(Sp,2);
|
||||
if Style=tlbsCRLF then
|
||||
continue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(Sp);
|
||||
if Style=tlbsCR then
|
||||
continue;
|
||||
end;
|
||||
if Assigned(Pointer(Result)) then
|
||||
Move(SLiteralStart^,Rp^,Pointer(SLiteralEnd)-Pointer(SLiteralStart)); { Byte difference to avoid signed div 2 on char = widechar. }
|
||||
Inc(Pointer(Rp),Pointer(SLiteralEnd)-Pointer(SLiteralStart)); { Again, byte difference. }
|
||||
if SLiteralEnd=Sp then
|
||||
break;
|
||||
SLiteralStart:=Sp;
|
||||
Inc(Rp,1+ord(Style=tlbsCRLF));
|
||||
if Assigned(Pointer(Result)) then
|
||||
begin
|
||||
if Style=tlbsCRLF then
|
||||
Rp[-2]:=#13;
|
||||
if Style=tlbsCR then
|
||||
Rp[-1]:=#13
|
||||
else
|
||||
Rp[-1]:=#10;
|
||||
end;
|
||||
until false;
|
||||
if Assigned(Pointer(Result)) then { Second pass finished. }
|
||||
break;
|
||||
if SLiteralStart=PChar(S) then { String is unchanged. }
|
||||
Exit(S);
|
||||
SetLength(Result,SizeUint(Pointer(Rp)-Pointer(Result)) div SizeOf(Char)); { Prepare second pass. }
|
||||
until false;
|
||||
end;
|
||||
|
||||
|
||||
|
72
tests/test/units/sysutils/tadjustlinebreaks.pp
Normal file
72
tests/test/units/sysutils/tadjustlinebreaks.pp
Normal file
@ -0,0 +1,72 @@
|
||||
{$mode objfpc} {$longstrings on} {$coperators on}
|
||||
uses
|
||||
SysUtils;
|
||||
|
||||
var
|
||||
somethingFailed: boolean = false;
|
||||
|
||||
function Repr(const s: string): string;
|
||||
var
|
||||
i: SizeInt;
|
||||
begin
|
||||
result := '';
|
||||
for i := 1 to length(s) do
|
||||
if (s[i] >= #32) and (s[i] <= #127) then
|
||||
result += s[i]
|
||||
else
|
||||
result += '#' + IntToStr(ord(s[i])) +
|
||||
specialize IfThen<string>((i < length(s)) and ((s[i] = #10) or (s[i] = #13) and (pChar(pointer(s))[i] <> #10)), LineEnding, '');
|
||||
end;
|
||||
|
||||
procedure TestAdjustLineBreaks(const src: string; style: TTextLineBreakStyle; expect: string);
|
||||
var
|
||||
got, styleName: string;
|
||||
begin
|
||||
got := AdjustLineBreaks(src, style);
|
||||
if got <> expect then
|
||||
begin
|
||||
WriteStr(styleName, style);
|
||||
writeln('AdjustLineBreaks(' + LineEnding +
|
||||
LineEnding +
|
||||
Repr(src) + ',' + LineEnding +
|
||||
LineEnding +
|
||||
styleName + ')' + LineEnding +
|
||||
LineEnding +
|
||||
'=' + LineEnding +
|
||||
LineEnding +
|
||||
Repr(got) + LineEnding +
|
||||
LineEnding +
|
||||
'expected' + LineEnding +
|
||||
LineEnding +
|
||||
Repr(expect) + LineEnding);
|
||||
somethingFailed := true;
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
D1 = 'Drinking the soup in the Dining Room will poison Viola and cause her to lose HP with each step.';
|
||||
D2 = 'The Chef will chop Viola''s hands off if she chooses to lend the chef a hand in the Kitchen.';
|
||||
D3 = 'Upon entering the Spider Room, If Viola takes the Butterfly without placing the Butterfly Model in the web, trying to exit the room will make a spider decapitate her.';
|
||||
D4 = 'Reading the Book of Death will cause Viola to violently and uncontrollably bleed to death.';
|
||||
D5 = 'Entering the Snake Room without feeding the Frog to the Snake will cause the Snake to eat Viola.';
|
||||
D6 = 'If Viola visits the Frog Room after the Frog was killed, and Viola reads the note, a black hand will emerge from the black pit and grab her.';
|
||||
LEs: array[TTextLineBreakStyle] of string = (#10, #13#10, #13);
|
||||
|
||||
var
|
||||
style: TTextLineBreakStyle;
|
||||
|
||||
begin
|
||||
for style in TTextLineBreakStyle do
|
||||
begin
|
||||
TestAdjustLineBreaks(
|
||||
#10#13 + D1 + #13#10 + D2 + #10 + D3 + #13 + D4 + #13#10#10, style,
|
||||
LEs[style] + LEs[style] + D1 + LEs[style] + D2 + LEs[style] + D3 + LEs[style] + D4 + LEs[style] + LEs[style]);
|
||||
|
||||
TestAdjustLineBreaks(
|
||||
D5 + #13 + D6, style,
|
||||
D5 + LEs[style] + D6);
|
||||
end;
|
||||
|
||||
if somethingFailed then halt(1);
|
||||
writeln('ok');
|
||||
end.
|
Loading…
Reference in New Issue
Block a user