* Externalized writer

* Fixed logfile parameter being ignored
This commit is contained in:
Andreas Schneider 2015-09-24 21:01:35 +02:00
parent dd0bade723
commit 3606a34054
5 changed files with 165 additions and 110 deletions

122
UApp.pas
View File

@ -19,29 +19,17 @@
unit UApp; unit UApp;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
{$modeswitch advancedrecords}
{.$define debugmatches} {.$define debugmatches}
interface interface
uses uses
Classes, SysUtils, CustApp, math, fgl, RegExpr, crt, Classes, SysUtils, CustApp, math, RegExpr,
UFilter; UFilter, UWriter;
type type
{ THighlight }
THighlight = record
FGColor: Byte;
BGColor: Byte;
Start: Integer;
Length: Integer;
class operator =(A, B: THighlight): Boolean;
end;
THighlights = specialize TFPGList<THighlight>;
{ TLogFilterApplication } { TLogFilterApplication }
TLogFilterApplication = class(TCustomApplication) TLogFilterApplication = class(TCustomApplication)
@ -51,6 +39,7 @@ type
FCommandMatcher: TRegExpr; FCommandMatcher: TRegExpr;
FCommandFileName: String; FCommandFileName: String;
FLogFileName: String; FLogFileName: String;
FWriter: TWriterList;
procedure DoRun; override; procedure DoRun; override;
procedure ProcessCommand(ACommand, AParams: String); procedure ProcessCommand(ACommand, AParams: String);
procedure WriteContent(AContent: String; AFilters: TFilterList; procedure WriteContent(AContent: String; AFilters: TFilterList;
@ -63,22 +52,6 @@ type
implementation implementation
{ THighlight }
class operator THighlight. = (A, B: THighlight): Boolean;
begin
Result := (A.Start = B.Start) and (A.Length = B.Length);
end;
function CompareHighlights(const AHL1: THighlight; const AHL2: THighlight): Integer;
begin
if AHL1.Start = AHL2.Start then
begin
Result := AHL1.Length - AHL2.Length;
end else
Result := AHL1.Start - AHL2.Start;
end;
{ TLogFilterApplication } { TLogFilterApplication }
procedure TLogFilterApplication.DoRun; procedure TLogFilterApplication.DoRun;
@ -119,6 +92,9 @@ begin
CloseFile(commandFile); CloseFile(commandFile);
if HasOption('f', 'logfile') then
FLogFileName := GetOptionValue('f', 'logfile');
if not FileExists(FLogFileName) then if not FileExists(FLogFileName) then
begin begin
Writeln('Logfile not found: ', FLogFileName); Writeln('Logfile not found: ', FLogFileName);
@ -127,6 +103,8 @@ begin
Exit; Exit;
end; end;
FWriter.Add(TConsoleWriter.Create);
AssignFile(logFile, FLogFileName); AssignFile(logFile, FLogFileName);
Reset(logFile); Reset(logFile);
@ -146,6 +124,7 @@ begin
CloseFile(logFile); CloseFile(logFile);
// One run is enough.
Terminate; Terminate;
end; end;
@ -174,85 +153,10 @@ end;
procedure TLogFilterApplication.WriteContent(AContent: String; procedure TLogFilterApplication.WriteContent(AContent: String;
AFilters: TFilterList; AGroupRanges: TGroupRanges); AFilters: TFilterList; AGroupRanges: TGroupRanges);
var var
i: Integer; writer: TWriter;
matchPos, offset, lastPos: Integer;
highlights: THighlights;
highlight: THighlight;
group: Byte;
begin begin
highlights := THighlights.Create; for writer in FWriter do
writer.WriteContent(AContent, AFilters, AGroupRanges);
offset := 0;
lastPos := 1;
for i := 0 to AFilters.Count - 1 do
begin
if AFilters[i].Expression.Exec(AContent) then
begin
repeat
// We need these values anyway.
matchPos := AFilters[i].Expression.MatchPos[0];
offset := AFilters[i].Expression.MatchLen[0];
group := AFilters[i].Group;
if group < Length(AGroupRanges) then
begin
if (matchPos + offset < AGroupRanges[group].StartIdx) or
(matchPos > AGroupRanges[group].EndIdx) then
continue; //Pointless; nothing we can do here
highlight.Start := Max(AGroupRanges[group].StartIdx, matchPos);
highlight.Length := Min(AGroupRanges[group].EndIdx - highlight.Start,
highlight.Start + offset - matchPos);
{$ifdef debugmatches}
writeln(' Highlight: ', highlight.Start, ', ', highlight.Length);
writeln(' MatchPos: ', matchPos, ', StartIdx: ', AGroupRanges[group].StartIdx);
writeln(' Offset: ', offset, ', EndIdx: ', AGroupRanges[group].EndIdx);
{$endif}
end else
begin
highlight.Start := matchPos;
highlight.Length := offset;
end;
highlight.FGColor := AFilters[i].FGColor;
highlight.BGColor := AFilters[i].BGColor;
highlights.Add(highlight);
until not AFilters[i].Expression.ExecNext;
end;
end;
highlights.Sort(@CompareHighlights);
// Sanitize highlights
for i := 0 to highlights.Count - 2 do
begin
if (highlights[i].Start + highlights[i].Length) > highlights[i+1].Start then
begin
highlight := highlights[i];
highlight.Length := highlights[i+1].Start - highlights[i].Start;
highlights[i] := highlight;
end;
end;
for highlight in highlights do
begin
matchPos := highlight.Start;
offset := highlight.Length;
write(Copy(AContent, lastPos, matchPos - lastPos));
if highlight.FGColor < $FF then
TextColor(highlight.FGColor);
if highlight.BGColor < $FF then
TextBackground(highlight.BGColor);
write(Copy(AContent, matchPos, offset));
NormVideo;
lastPos := matchPos + offset;
end;
writeln(Copy(AContent, lastPos, Length(AContent)));
highlights.Free;
end; end;
constructor TLogFilterApplication.Create(TheOwner: TComponent); constructor TLogFilterApplication.Create(TheOwner: TComponent);
@ -260,12 +164,14 @@ begin
inherited Create(TheOwner); inherited Create(TheOwner);
FLineFilters := TLineFilters.Create; FLineFilters := TLineFilters.Create;
FCommandMatcher := TRegExpr.Create('^(\w+)( (.*)|)$'); // 1 = command, 3 = OPTIONAL params FCommandMatcher := TRegExpr.Create('^(\w+)( (.*)|)$'); // 1 = command, 3 = OPTIONAL params
FWriter := TWriterList.Create;
end; end;
destructor TLogFilterApplication.Destroy; destructor TLogFilterApplication.Destroy;
begin begin
FLineFilters.Free; FLineFilters.Free;
FCommandMatcher.Free; FCommandMatcher.Free;
FWriter.Free;
inherited Destroy; inherited Destroy;
end; end;

View File

@ -19,6 +19,7 @@
unit UFilter; unit UFilter;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
{$modeswitch advancedrecords}
{.$define debugmatches} {.$define debugmatches}
@ -65,6 +66,19 @@ type
end; end;
TLineFilters = specialize TFPGObjectList<TLineFilter>; TLineFilters = specialize TFPGObjectList<TLineFilter>;
{ THighlight }
THighlight = record
FGColor: Byte;
BGColor: Byte;
Start: Integer;
Length: Integer;
class operator =(A, B: THighlight): Boolean;
end;
THighlights = specialize TFPGList<THighlight>;
function CompareHighlights(const AHL1: THighlight; const AHL2: THighlight): Integer;
implementation implementation
{ THighlightFilter } { THighlightFilter }
@ -130,6 +144,22 @@ begin
end; end;
end; end;
{ THighlight }
class operator THighlight. = (A, B: THighlight): Boolean;
begin
Result := (A.Start = B.Start) and (A.Length = B.Length);
end;
function CompareHighlights(const AHL1: THighlight; const AHL2: THighlight): Integer;
begin
if AHL1.Start = AHL2.Start then
begin
Result := AHL1.Length - AHL2.Length;
end else
Result := AHL1.Start - AHL2.Start;
end;
initialization initialization
THighlightFilter.FilterExpression := TRegExpr.Create('( (FG|BG|Grp)(\d+))*$'); THighlightFilter.FilterExpression := TRegExpr.Create('( (FG|BG|Grp)(\d+))*$');
THighlightFilter.ParamExpression := TRegExpr.Create('(FG|BG|Grp)(\d+)'); THighlightFilter.ParamExpression := TRegExpr.Create('(FG|BG|Grp)(\d+)');

115
UWriter.pas Normal file
View File

@ -0,0 +1,115 @@
unit UWriter;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, UFilter, Math, crt, fgl;
type
TWriter = class
public
procedure WriteContent(AContent: String; AFilters: TFilterList;
AGroupRanges: TGroupRanges); virtual; abstract;
end;
TWriterList = specialize TFPGObjectList<TWriter>;
{ TConsoleWriter }
TConsoleWriter = class(TWriter)
public
procedure WriteContent(AContent: String; AFilters: TFilterList;
AGroupRanges: TGroupRanges); override;
end;
implementation
{ TConsoleWriter }
procedure TConsoleWriter.WriteContent(AContent: String; AFilters: TFilterList;
AGroupRanges: TGroupRanges);
var
i: Integer;
matchPos, offset, lastPos: Integer;
highlights: THighlights;
highlight: THighlight;
group: Byte;
begin
highlights := THighlights.Create;
offset := 0;
lastPos := 1;
for i := 0 to AFilters.Count - 1 do
begin
if AFilters[i].Expression.Exec(AContent) then
begin
repeat
// We need these values anyway.
matchPos := AFilters[i].Expression.MatchPos[0];
offset := AFilters[i].Expression.MatchLen[0];
group := AFilters[i].Group;
if group < Length(AGroupRanges) then
begin
if (matchPos + offset < AGroupRanges[group].StartIdx) or
(matchPos > AGroupRanges[group].EndIdx) then
continue; //Pointless; nothing we can do here
highlight.Start := Max(AGroupRanges[group].StartIdx, matchPos);
highlight.Length := Min(AGroupRanges[group].EndIdx - highlight.Start,
highlight.Start + offset - matchPos);
{$ifdef debugmatches}
writeln(' Highlight: ', highlight.Start, ', ', highlight.Length);
writeln(' MatchPos: ', matchPos, ', StartIdx: ', AGroupRanges[group].StartIdx);
writeln(' Offset: ', offset, ', EndIdx: ', AGroupRanges[group].EndIdx);
{$endif}
end else
begin
highlight.Start := matchPos;
highlight.Length := offset;
end;
highlight.FGColor := AFilters[i].FGColor;
highlight.BGColor := AFilters[i].BGColor;
highlights.Add(highlight);
until not AFilters[i].Expression.ExecNext;
end;
end;
highlights.Sort(@CompareHighlights);
// Sanitize highlights
for i := 0 to highlights.Count - 2 do
begin
if (highlights[i].Start + highlights[i].Length) > highlights[i+1].Start then
begin
highlight := highlights[i];
highlight.Length := highlights[i+1].Start - highlights[i].Start;
highlights[i] := highlight;
end;
end;
for highlight in highlights do
begin
matchPos := highlight.Start;
offset := highlight.Length;
write(Copy(AContent, lastPos, matchPos - lastPos));
if highlight.FGColor < $FF then
TextColor(highlight.FGColor);
if highlight.BGColor < $FF then
TextBackground(highlight.BGColor);
write(Copy(AContent, matchPos, offset));
NormVideo;
lastPos := matchPos + offset;
end;
writeln(Copy(AContent, lastPos, Length(AContent)));
highlights.Free;
end;
end.

View File

@ -54,7 +54,7 @@
<FormatVersion Value="1"/> <FormatVersion Value="1"/>
</local> </local>
</RunParams> </RunParams>
<Units Count="3"> <Units Count="4">
<Unit0> <Unit0>
<Filename Value="logfilter.pas"/> <Filename Value="logfilter.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -67,6 +67,10 @@
<Filename Value="UApp.pas"/> <Filename Value="UApp.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit2> </Unit2>
<Unit3>
<Filename Value="UWriter.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -21,7 +21,7 @@ program logfilter;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
uses uses
Classes, SysUtils, UApp, UFilter; Classes, SysUtils, UApp, UFilter, UWriter;
var var
Application: TLogFilterApplication; Application: TLogFilterApplication;