mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-31 09:21:35 +02:00
codetools: fpc msg parser: chomp space at end
git-svn-id: trunk@35145 -
This commit is contained in:
parent
55508054d4
commit
d84134d94e
@ -45,6 +45,15 @@ uses
|
||||
Classes, SysUtils, FileProcs, AVL_Tree;
|
||||
|
||||
type
|
||||
TfmiSpecialItem = (
|
||||
fmisiNone,
|
||||
fmisiFatal,
|
||||
fmisiError,
|
||||
fmisiWarning,
|
||||
fmisiNote,
|
||||
fmisiHint
|
||||
);
|
||||
TfmiSpecialItems = set of TfmiSpecialItem;
|
||||
|
||||
{ TFPCMsgItem }
|
||||
|
||||
@ -55,24 +64,27 @@ type
|
||||
TxtIdentifier: string; // identifier
|
||||
ID: integer; // positive number
|
||||
ShownTyp: string; // e.g. shown Typ, can be different from Typ
|
||||
Msg: string; // Msg with placeholders $1 .. $9
|
||||
Pattern: string; // Text with placeholders $1 .. $9
|
||||
PatternEndSpace: string;
|
||||
Comment: string; // multi line
|
||||
|
||||
Index: integer; // index in list
|
||||
function GetName(WithID: boolean = true): string;
|
||||
function MsgFits(const aMsg: string): integer; // >=0 fits
|
||||
function PatternFits(aMsg: string): integer; // >=0 fits
|
||||
end;
|
||||
|
||||
{ TFPCMsgFile }
|
||||
|
||||
TFPCMsgFile = class
|
||||
private
|
||||
fSpecialItems: array[TfmiSpecialItem] of TFPCMsgItem;
|
||||
FItems: TFPList; // list of TFPCMsgItem
|
||||
fSortedForID: TAVLTree; // tree of TFPCMsgItem sorted for ID
|
||||
fItemById: array of TFPCMsgItem;
|
||||
fNodeMgr: TAVLTreeNodeMemManager;
|
||||
function GetItems(Index: integer): TFPCMsgItem;
|
||||
procedure CreateArray;
|
||||
function GetSpecialItems(Index: TfmiSpecialItem): TFPCMsgItem;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
@ -83,7 +95,9 @@ type
|
||||
function Count: integer;
|
||||
property Items[Index: integer]: TFPCMsgItem read GetItems; default;
|
||||
function FindWithID(ID: integer): TFPCMsgItem;
|
||||
function FindWithMessage(const Msg: string): TFPCMsgItem;
|
||||
function FindWithMessage(Msg: string): TFPCMsgItem;
|
||||
function GetMsgText(Item: TFPCMsgItem): string; // prepends msg type (e.g. Error:)
|
||||
property SpecialItems[Index: TfmiSpecialItem]: TFPCMsgItem read GetSpecialItems;
|
||||
end;
|
||||
|
||||
function CompareFPCMsgId(item1, item2: Pointer): integer;
|
||||
@ -113,6 +127,8 @@ type
|
||||
|
||||
procedure ExtractFPCMsgParameters(const Mask, Txt: string; var Ranges: TFPCMsgRanges);
|
||||
|
||||
function dbgs(i: TfmiSpecialItem): string; overload;
|
||||
|
||||
implementation
|
||||
|
||||
function CompareFPCMsgId(item1, item2: Pointer): integer;
|
||||
@ -217,6 +233,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function dbgs(i: TfmiSpecialItem): string;
|
||||
begin
|
||||
case i of
|
||||
fmisiFatal: Result:='fatal';
|
||||
fmisiError: Result:='error';
|
||||
fmisiWarning: Result:='warning';
|
||||
fmisiNote: Result:='note';
|
||||
fmisiHint: Result:='hint';
|
||||
else Result:='?';
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TFPCMsgItem }
|
||||
|
||||
function TFPCMsgItem.GetName(WithID: boolean): string;
|
||||
@ -228,7 +256,7 @@ begin
|
||||
Result:=Result+'='+IntToStr(ID);
|
||||
end;
|
||||
|
||||
function TFPCMsgItem.MsgFits(const aMsg: string): integer;
|
||||
function TFPCMsgItem.PatternFits(aMsg: string): integer;
|
||||
var
|
||||
PatStartPos: PChar;
|
||||
PatEndPos: PChar;
|
||||
@ -237,26 +265,28 @@ var
|
||||
MsgPos: PChar;
|
||||
PatPos: PChar;
|
||||
MsgStartPos: PChar;
|
||||
PatLen: Integer;
|
||||
begin
|
||||
Result:=-1;
|
||||
// Msg is for example "$1 lines compiled, $2 sec$3"
|
||||
if (aMsg='') or (Msg='') then exit;
|
||||
// Pattern is for example "$1 lines compiled, $2 sec$3"
|
||||
if (aMsg='') or (Pattern='') then exit;
|
||||
|
||||
// aMsg can start with a filename => hard to tell where the message starts
|
||||
// the Msg is always at the end of aMsg => quick check the end
|
||||
if (length(aMsg)>=2)
|
||||
and ((aMsg[Length(aMsg)-1]<>'$') or (not (aMsg[Length(aMsg)] in ['0'..'9'])))
|
||||
// the Pattern is always at the end of aMsg => quick check the end
|
||||
PatLen:=length(Pattern);
|
||||
if (PatLen>=2)
|
||||
and ((Pattern[PatLen-1]<>'$') or (not (Pattern[PatLen] in ['0'..'9'])))
|
||||
then begin
|
||||
// the pattern does not have a placeholder at the end
|
||||
// => the tail must be the pattern => check tail
|
||||
PatStartPos:=PChar(Msg);
|
||||
PatEndPos:=@aMsg[length(aMsg)];
|
||||
MsgPos:=@Msg[length(Msg)];
|
||||
MsgStartPos:=PChar(Msg);
|
||||
PatStartPos:=PChar(Pattern);
|
||||
PatEndPos:=@Pattern[PatLen];
|
||||
MsgPos:=@aMsg[length(aMsg)];
|
||||
MsgStartPos:=PChar(aMsg);
|
||||
while (PatEndPos^=MsgPos^) do begin
|
||||
if PatEndPos=PatStartPos then begin
|
||||
// pattern has no placeholders and whole pattern fits
|
||||
Result:=length(Msg);
|
||||
Result:=PatLen;
|
||||
exit;
|
||||
end;
|
||||
dec(PatEndPos);
|
||||
@ -273,8 +303,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
PatEndPos:=PChar(aMsg);
|
||||
MsgFitPos:=PChar(Msg);
|
||||
PatEndPos:=PChar(Pattern);
|
||||
MsgFitPos:=PChar(aMsg);
|
||||
MatchLen:=0;
|
||||
repeat
|
||||
PatStartPos:=PatEndPos;
|
||||
@ -285,7 +315,7 @@ begin
|
||||
inc(PatEndPos);
|
||||
until false;
|
||||
if PatEndPos<>PatStartPos then begin
|
||||
// search pattern in Msg
|
||||
// search pattern in Pattern
|
||||
repeat
|
||||
MsgPos:=MsgFitPos;
|
||||
PatPos:=PatStartPos;
|
||||
@ -335,13 +365,13 @@ begin
|
||||
Item:=TFPCMsgItem(fSortedForID.FindLowest.Data);
|
||||
MinID:=Item.ID;
|
||||
if MinID<0 then begin
|
||||
debugln(['TFPCMsgFile.CreateArray WARNING: MinID ',MinID,' too low: ',Item.Msg]);
|
||||
debugln(['TFPCMsgFile.CreateArray WARNING: MinID ',MinID,' too low: ',Item.Pattern]);
|
||||
exit;
|
||||
end;
|
||||
Item:=TFPCMsgItem(fSortedForID.FindHighest.Data);
|
||||
MaxID:=Item.ID;
|
||||
if MaxID>100000 then begin
|
||||
debugln(['TFPCMsgFile.CreateArray WARNING: MaxID ',MaxID,' too high: ',Item.Msg]);
|
||||
debugln(['TFPCMsgFile.CreateArray WARNING: MaxID ',MaxID,' too high: ',Item.Pattern]);
|
||||
exit;
|
||||
end;
|
||||
//debugln(['TFPCMsgFile.CreateArray Max=',MaxID]);
|
||||
@ -349,11 +379,16 @@ begin
|
||||
for i:=0 to length(fItemById)-1 do fItemById[i]:=nil;
|
||||
for i:=0 to FItems.Count-1 do begin
|
||||
Item:=TFPCMsgItem(FItems[i]);
|
||||
//debugln(['TFPCMsgFile.CreateArray ',Item.ID,' ',copy(Item.Msg,1,20),'..',copy(Item.Msg,length(Item.Msg)-19,20)]);
|
||||
//debugln(['TFPCMsgFile.CreateArray ',Item.ID,' ',copy(Item.Pattern,1,20),'..',copy(Item.Pattern,length(Item.Pattern)-19,20)]);
|
||||
fItemById[Item.ID]:=Item;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFPCMsgFile.GetSpecialItems(Index: TfmiSpecialItem): TFPCMsgItem;
|
||||
begin
|
||||
Result:=fSpecialItems[Index];
|
||||
end;
|
||||
|
||||
constructor TFPCMsgFile.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
@ -429,6 +464,8 @@ procedure TFPCMsgFile.LoadFromList(List: TStrings);
|
||||
ID: LongInt;
|
||||
Msg: string;
|
||||
h: string;
|
||||
i: Integer;
|
||||
MsgEndSpace: String;
|
||||
begin
|
||||
Result:=nil;
|
||||
p:=PChar(s);
|
||||
@ -494,14 +531,23 @@ procedure TFPCMsgFile.LoadFromList(List: TStrings);
|
||||
until false;
|
||||
end;
|
||||
|
||||
i:=length(Msg);
|
||||
while (i>=1) and (Msg[i] in [' ',#9,#10,#13]) do dec(i);
|
||||
if i<length(Msg) then begin
|
||||
MsgEndSpace:=copy(Msg,i+1,length(Msg));
|
||||
System.Delete(Msg,i+1,length(Msg));
|
||||
end else
|
||||
MsgEndSpace:='';
|
||||
|
||||
Result:=TFPCMsgItem.Create;
|
||||
Result.Part:=Part;
|
||||
Result.Typ:=Typ;
|
||||
Result.TxtIdentifier:=TxtID;
|
||||
Result.ID:=ID;
|
||||
Result.ShownTyp:=ShownTyp;
|
||||
Result.Msg:=Msg;
|
||||
//debugln(['ReadItem Part=',Part,' Typ=',Typ,' TxtID=',TxtID,' ID=',ID,' IdTyp=',ShownTyp,' Msg="',copy(Result.Msg,1,20),'"']);
|
||||
Result.Pattern:=Msg;
|
||||
Result.PatternEndSpace:=MsgEndSpace;
|
||||
//debugln(['ReadItem Part=',Part,' Typ=',Typ,' TxtID=',TxtID,' ID=',ID,' IdTyp=',ShownTyp,' Msg="',copy(Result.Pattern,1,20),'"']);
|
||||
end;
|
||||
|
||||
var
|
||||
@ -530,10 +576,17 @@ begin
|
||||
end else begin
|
||||
Item:=ReadItem(Line,s);
|
||||
if Item<>nil then begin
|
||||
//debugln(['TFPCMsgFile.LoadFromList ',Item.ID,' ',Item.Msg]);
|
||||
//debugln(['TFPCMsgFile.LoadFromList ',Item.ID,' ',Item.Pattern]);
|
||||
Item.Index:=FItems.Count;
|
||||
FItems.Add(Item);
|
||||
fSortedForID.Add(Item);
|
||||
case Item.ID of
|
||||
1012: fSpecialItems[fmisiFatal]:=Item;
|
||||
1013: fSpecialItems[fmisiError]:=Item;
|
||||
1014: fSpecialItems[fmisiWarning]:=Item;
|
||||
1015: fSpecialItems[fmisiNote]:=Item;
|
||||
1016: fSpecialItems[fmisiHint]:=Item;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
inc(Line);
|
||||
@ -558,7 +611,10 @@ end;
|
||||
procedure TFPCMsgFile.Clear;
|
||||
var
|
||||
i: Integer;
|
||||
s: TfmiSpecialItem;
|
||||
begin
|
||||
for s:=Low(fSpecialItems) to high(fSpecialItems) do
|
||||
fSpecialItems[s]:=nil;
|
||||
SetLength(fItemById,0);
|
||||
fSortedForID.Clear;
|
||||
for i:=0 to FItems.Count-1 do
|
||||
@ -587,7 +643,7 @@ begin
|
||||
Result:=nil;
|
||||
end;
|
||||
|
||||
function TFPCMsgFile.FindWithMessage(const Msg: string): TFPCMsgItem;
|
||||
function TFPCMsgFile.FindWithMessage(Msg: string): TFPCMsgItem;
|
||||
var
|
||||
MsgID: Integer;
|
||||
Item: TFPCMsgItem;
|
||||
@ -598,6 +654,8 @@ var
|
||||
begin
|
||||
Result:=nil;
|
||||
if Msg='' then exit;
|
||||
Msg:=Trim(Msg);
|
||||
if Msg='' then exit;
|
||||
p:=PChar(Msg);
|
||||
|
||||
// skip time [0.000]
|
||||
@ -629,8 +687,8 @@ begin
|
||||
BestMatchLen:=-1;
|
||||
for i:=0 to Count-1 do begin
|
||||
Item:=Items[i];
|
||||
if Item.Msg='' then continue;
|
||||
MatchLen:=Item.MsgFits(Msg);
|
||||
if Item.Pattern='' then continue;
|
||||
MatchLen:=Item.PatternFits(Msg);
|
||||
if MatchLen>BestMatchLen then begin
|
||||
BestMatchLen:=MatchLen;
|
||||
Result:=Item;
|
||||
@ -638,6 +696,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFPCMsgFile.GetMsgText(Item: TFPCMsgItem): string;
|
||||
var
|
||||
si: TfmiSpecialItem;
|
||||
begin
|
||||
if Item=nil then exit('');
|
||||
Result:=Item.Pattern;
|
||||
if length(Item.Typ)=1 then begin
|
||||
case Item.Typ[1] of
|
||||
'f': si:=fmisiFatal;
|
||||
'e': si:=fmisiError;
|
||||
'w': si:=fmisiWarning;
|
||||
'n': si:=fmisiNote;
|
||||
'h': si:=fmisiHint;
|
||||
else si:=fmisiNone;
|
||||
end;
|
||||
if (si<>fmisiNone) and (fSpecialItems[si]<>nil) then
|
||||
Result:=fSpecialItems[si].Pattern+' '+Result;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TFPCMsgRanges }
|
||||
|
||||
procedure TFPCMsgRanges.Add(StartPos, EndPos: integer);
|
||||
|
@ -38,6 +38,8 @@ var
|
||||
i: Integer;
|
||||
Found: TFPCMsgItem;
|
||||
Item: TFPCMsgItem;
|
||||
Msg: String;
|
||||
s: TfmiSpecialItem;
|
||||
begin
|
||||
if Paramcount<>1 then begin
|
||||
writeln('Usage: '+ParamStr(0)+' fpc_file_errore.msg');
|
||||
@ -53,17 +55,35 @@ begin
|
||||
|
||||
MsgFile:=TFPCMsgFile.Create;
|
||||
MsgFile.LoadFromText(Code.Source);
|
||||
for s:=succ(fmisiNone) to high(TfmiSpecialItem) do
|
||||
if MsgFile.SpecialItems[s]=nil then
|
||||
raise Exception.Create('special message '+dbgs(s)+' is missing');
|
||||
|
||||
// check a specific message
|
||||
Item:=MsgFile.FindWithID(1009);
|
||||
Msg:=MsgFile.GetMsgText(Item);
|
||||
if Item.PatternFits(Msg)<0 then begin
|
||||
writeln('message does not fit itself: ',Item.GetName,'="',Item.Pattern,'"');
|
||||
writeln('Msg: ',Msg);
|
||||
writeln('Fits=',Item.PatternFits(Msg));
|
||||
raise Exception.Create('bug?');
|
||||
end;
|
||||
|
||||
for i:=0 to MsgFile.Count-1 do begin
|
||||
Item:=MsgFile[i];
|
||||
Found:=MsgFile.FindWithMessage(Item.Msg);
|
||||
Msg:=MsgFile.GetMsgText(Item);
|
||||
Found:=MsgFile.FindWithMessage(Msg);
|
||||
if Found=nil then begin
|
||||
// this should never happen
|
||||
writeln('message does not fit itself: i=',i,
|
||||
' MsgFile[i]=',Item.GetName,'="',Item.Msg,'"');
|
||||
' MsgFile[i]=',Item.GetName,'="',Item.Pattern,'"');
|
||||
writeln('Msg: ',Msg);
|
||||
writeln('Fits=',Item.PatternFits(Msg));
|
||||
raise Exception.Create('bug?');
|
||||
end else if Found<>Item then begin
|
||||
writeln('message pattern is ambiguous: i=',i,
|
||||
' MsgFile[i]=',Item.GetName,'="',Item.Msg,'"',
|
||||
' Other=',Found.GetName,'="',Found.Msg,'"');
|
||||
' MsgFile[i]=',Item.GetName,'="',Item.Pattern,'"',
|
||||
' Other=',Found.GetName,'="',Found.Pattern,'"');
|
||||
end;
|
||||
end;
|
||||
MsgFile.Free;
|
||||
|
Loading…
Reference in New Issue
Block a user