I have a routine that processes a C-like string, resulting in usual Delphi string:
class function UTIL.ProcessString(const S: string): string;
var
SB:TStringBuilder;
P:MarshaledString;
procedure DoIt(const S:string;const I:Integer=2);
begin
SB.Append(S);
Inc(P,I);
end;
begin
SB:=TStringBuilder.Create;
P:=PChar(S);
while P<>nil do
begin
if P^<>'\' then DoIt(P^,1) else
case (P+1)^ of
'\','"':DoIt((P+1)^);
#0,'n':DoIt(sLineBreak);
't':DoIt(#9);
else DoIt('\'+(P+1)^,2);
end;
end;
Result:=SB.ToString;
SB.Free;
end;
The problem is the loop never exits. Debugging shows the line while P<>nil do
doesn't evaluate to False because P is '' at the end of processing, so the code tries to perform out-of-range operations on it. Since I didn't find any concise documentation on pointer math in Delphi, it's quite possible I'm at fault here.
EDIT: I've rewritten the function with everything read in mind like that:
class function UTIL.ProcessString(const S: string): string;
var
SB:TStringBuilder;
P:PChar;
C:Char;
begin
SB:=TStringBuilder.Create;
P:=PChar(S);
repeat
C:=P^;
Inc(P);
case C of
#0:;
'\':
begin
C:=P^;
Inc(P);
case C of
#0,'n':SB.Append(sLineBreak);
'\','"':SB.Append(C);
't':SB.Append(#9);
else SB.Append('\').Append(C);
end;
end;
else SB.Append(C);
end;
until P^=#0;
Result:=SB.ToString;
SB.Free;
end;
I check for #0
in the inner case statement for "such \
strings"
being fed into the routine, i. e. a sequence of strings broken into pieces read from a source and then formatted one by one. So far this works great, however it fails to correctly parse '\\t'
as '\t'
and similar constructs, it returns just #9
. I can't really think of any cause. Oh, and the old version also had this bug BTW.