diff --git a/UApp.pas b/UApp.pas index 4662fa8..69b55dc 100644 --- a/UApp.pas +++ b/UApp.pas @@ -19,29 +19,17 @@ unit UApp; {$mode objfpc}{$H+} -{$modeswitch advancedrecords} {.$define debugmatches} interface uses - Classes, SysUtils, CustApp, math, fgl, RegExpr, crt, - UFilter; + Classes, SysUtils, CustApp, math, RegExpr, + UFilter, UWriter; type - { THighlight } - - THighlight = record - FGColor: Byte; - BGColor: Byte; - Start: Integer; - Length: Integer; - class operator =(A, B: THighlight): Boolean; - end; - THighlights = specialize TFPGList; - { TLogFilterApplication } TLogFilterApplication = class(TCustomApplication) @@ -51,6 +39,7 @@ type FCommandMatcher: TRegExpr; FCommandFileName: String; FLogFileName: String; + FWriter: TWriterList; procedure DoRun; override; procedure ProcessCommand(ACommand, AParams: String); procedure WriteContent(AContent: String; AFilters: TFilterList; @@ -63,22 +52,6 @@ type 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 } procedure TLogFilterApplication.DoRun; @@ -119,6 +92,9 @@ begin CloseFile(commandFile); + if HasOption('f', 'logfile') then + FLogFileName := GetOptionValue('f', 'logfile'); + if not FileExists(FLogFileName) then begin Writeln('Logfile not found: ', FLogFileName); @@ -127,6 +103,8 @@ begin Exit; end; + FWriter.Add(TConsoleWriter.Create); + AssignFile(logFile, FLogFileName); Reset(logFile); @@ -146,6 +124,7 @@ begin CloseFile(logFile); + // One run is enough. Terminate; end; @@ -174,85 +153,10 @@ end; procedure TLogFilterApplication.WriteContent(AContent: String; AFilters: TFilterList; AGroupRanges: TGroupRanges); var - i: Integer; - matchPos, offset, lastPos: Integer; - highlights: THighlights; - highlight: THighlight; - group: Byte; + writer: TWriter; 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; + for writer in FWriter do + writer.WriteContent(AContent, AFilters, AGroupRanges); end; constructor TLogFilterApplication.Create(TheOwner: TComponent); @@ -260,12 +164,14 @@ begin inherited Create(TheOwner); FLineFilters := TLineFilters.Create; FCommandMatcher := TRegExpr.Create('^(\w+)( (.*)|)$'); // 1 = command, 3 = OPTIONAL params + FWriter := TWriterList.Create; end; destructor TLogFilterApplication.Destroy; begin FLineFilters.Free; FCommandMatcher.Free; + FWriter.Free; inherited Destroy; end; diff --git a/UFilter.pas b/UFilter.pas index 3cda62a..ee8e8e8 100644 --- a/UFilter.pas +++ b/UFilter.pas @@ -19,6 +19,7 @@ unit UFilter; {$mode objfpc}{$H+} +{$modeswitch advancedrecords} {.$define debugmatches} @@ -65,6 +66,19 @@ type end; TLineFilters = specialize TFPGObjectList; + { THighlight } + + THighlight = record + FGColor: Byte; + BGColor: Byte; + Start: Integer; + Length: Integer; + class operator =(A, B: THighlight): Boolean; + end; + THighlights = specialize TFPGList; + +function CompareHighlights(const AHL1: THighlight; const AHL2: THighlight): Integer; + implementation { THighlightFilter } @@ -130,6 +144,22 @@ begin 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 THighlightFilter.FilterExpression := TRegExpr.Create('( (FG|BG|Grp)(\d+))*$'); THighlightFilter.ParamExpression := TRegExpr.Create('(FG|BG|Grp)(\d+)'); diff --git a/UWriter.pas b/UWriter.pas new file mode 100644 index 0000000..8c1cb14 --- /dev/null +++ b/UWriter.pas @@ -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; + + { 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. + diff --git a/logfilter.lpi b/logfilter.lpi index 43e9ade..037c22c 100644 --- a/logfilter.lpi +++ b/logfilter.lpi @@ -54,7 +54,7 @@ - + @@ -67,6 +67,10 @@ + + + + diff --git a/logfilter.pas b/logfilter.pas index d658309..83ebe82 100644 --- a/logfilter.pas +++ b/logfilter.pas @@ -21,7 +21,7 @@ program logfilter; {$mode objfpc}{$H+} uses - Classes, SysUtils, UApp, UFilter; + Classes, SysUtils, UApp, UFilter, UWriter; var Application: TLogFilterApplication;