source: trunk/linetime.lpr

Last change on this file was 7, checked in by chronos, 9 years ago
  • Fixed: Proper evaluation of termination string.
File size: 7.2 KB
Line 
1program linetime;
2
3{$mode objfpc}{$H+}
4
5uses
6 {$IFDEF UNIX}{$IFDEF UseCThreads}
7 cthreads,
8 {$ENDIF}{$ENDIF}
9 Classes, SysUtils, CustApp
10 { you can add units after this }
11 ,DateUtils, IOStream;
12
13type
14
15 { TMyApplication }
16
17 TMyApplication = class(TCustomApplication)
18 protected
19 procedure DoRun; override;
20 private
21 UseEscapeChars: Boolean;
22 TestMode: Boolean;
23 TestLineDelay: TDateTime;
24 TestString: string;
25 FirstLine: Boolean;
26 TextOnLine: Boolean;
27 StartTime: TDateTime;
28 NewLine: Boolean;
29 NewLineEnding: string;
30 ShowTime: Boolean;
31 LastLineTime: TDateTime;
32 LogFile: TFileStream;
33 LogEnabled: Boolean;
34 TermString: string;
35 TermStringIndex: Integer;
36 procedure TermCheckString(Buffer: string);
37 function FindLineEnding(Buffer: string; var FoundLineEnding: string): Integer;
38 procedure WriteRaw(Text: string);
39 procedure WriteLog(Text: string);
40 procedure PrintOutput(Output: string);
41 procedure ShowTimePrefix;
42 procedure ProcessBuffer(Buffer: string);
43 public
44 FormatCSV: Boolean;
45 constructor Create(TheOwner: TComponent); override;
46 destructor Destroy; override;
47 procedure WriteHelp; virtual;
48 end;
49
50{ TMyApplication }
51
52procedure TMyApplication.DoRun;
53var
54 ErrorMsg: String;
55 Buffer: string;
56 InputStream: TStream;
57 Count: Integer;
58 LogDir: string;
59 FileName: string;
60begin
61 // Quick check parameters
62 ErrorMsg := CheckOptions('hclt:e', 'help csv log termstr escape');
63 if ErrorMsg <> '' then begin
64 ShowException(Exception.Create(ErrorMsg));
65 Terminate;
66 Exit;
67 end;
68
69 // Parse parameters
70 if HasOption('h', 'help') then begin
71 WriteHelp;
72 Terminate;
73 Exit;
74 end;
75
76 if HasOption('t', 'termstr') then begin
77 TermString := GetOptionValue('t', 'termstr');
78 end else TermString := '';
79
80 FormatCSV := HasOption('c', 'csv');
81 UseEscapeChars := HasOption('e', 'escape');
82 LogEnabled := HasOption('l', 'log');
83 if LogEnabled then begin
84 LogDir := GetUserDir + DirectorySeparator + '.linetime' + DirectorySeparator + 'logs';
85 ForceDirectories(LogDir);
86 FileName := LogDir + DirectorySeparator + FormatDateTime('yyyymmddhhnnss', Now) + '.log';
87 LogFile := TFileStream.Create(FileName, fmCreate);
88 end;
89
90 NewLine := True;
91 ShowTime := True;
92 FirstLine := True;
93 StartTime := Now;
94 LastLineTime := 0;
95 TermStringIndex := 1;
96 TextOnLine := False;
97 try
98 if TestMode then begin
99 InputStream := TMemoryStream.Create;
100 InputStream.Write(TestString[1], Length(TestString));
101 InputStream.Position := 0;
102 end else
103 InputStream := TIOStream.Create(iosInput);
104 repeat
105 SetLength(Buffer, 1000);
106 Count := InputStream.Read(Buffer[1], Length(Buffer));
107 SetLength(Buffer, Count);
108 ProcessBuffer(Buffer);
109 until (Count = 0) or Terminated;
110 NewLineEnding := LineEnding;
111 PrintOutput('');
112 finally
113 InputStream.Free;
114 end;
115 WriteRaw(LineEnding);
116 WriteLog(LineEnding);
117
118 Terminate;
119end;
120
121procedure TMyApplication.TermCheckString(Buffer: string);
122var
123 I: Integer;
124begin
125 // Search for termination string
126 if TermString <> '' then
127 for I := 1 to Length(Buffer) do begin
128 if TermStringIndex > Length(TermString) then begin
129 Terminate;
130 Break;
131 end;
132 if Buffer[I] = TermString[TermStringIndex] then
133 Inc(TermStringIndex)
134 else TermStringIndex := 1;
135 end;
136end;
137
138function TMyApplication.FindLineEnding(Buffer: string; var FoundLineEnding: string): Integer;
139const
140 LineEnding1 = #13#10;
141 LineEnding2 = #10;
142 LineEnding3 = #13;
143var
144 P: Integer;
145begin
146 Result := 0;
147 FoundLineEnding := '';
148
149 P := Pos(LineEnding1, Buffer);
150 if (P > 0) and (((Result > 0) and (P < Result)) or (Result = 0)) then begin
151 Result := P;
152 FoundLineEnding := LineEnding1;
153 end;
154 P := Pos(LineEnding2, Buffer);
155 if (P > 0) and (((Result > 0) and (P < Result)) or (Result = 0)) then begin
156 Result := P;
157 FoundLineEnding := LineEnding2;
158 end;
159 P := Pos(LineEnding3, Buffer);
160 if (P > 0) and (((Result > 0) and (P < Result)) or (Result = 0)) then begin
161 Result := P;
162 FoundLineEnding := LineEnding3;
163 end;
164end;
165
166procedure TMyApplication.WriteRaw(Text: string);
167begin
168 Write(Text);
169end;
170
171procedure TMyApplication.WriteLog(Text: string);
172begin
173 if LogEnabled then begin
174 if Length(Text) > 0 then
175 LogFile.Write(Text[1], Length(Text));
176 end;
177end;
178
179procedure TMyApplication.PrintOutput(Output: string);
180begin
181 TermCheckString(Output);
182 if NewLine then begin
183 if not FirstLine then begin
184 // If previous line was empty then print time prefix before move to next line
185 if (not TextOnLine) then ShowTimePrefix;
186 if FormatCSV then begin
187 WriteRaw('"' + LineEnding);
188 end else begin
189 WriteRaw(NewLineEnding);
190 end;
191 TextOnLine := False;
192 end;
193 WriteLog(LineEnding);
194 NewLine := False;
195 FirstLine := False;
196 end;
197 if Length(Output) > 0 then TextOnLine := True;
198 if TextOnLine and ShowTime then begin
199 ShowTimePrefix;
200 ShowTime := False;
201 end;
202 WriteRaw(Output);
203 WriteLog(Output);
204end;
205
206procedure TMyApplication.ShowTimePrefix;
207var
208 LineTime: TDateTime;
209 TimeStr: string;
210begin
211 LineTime := Now - StartTime;
212 TimeStr := FloatToStrF(LineTime / OneSecond, ffFixed, 10, 2);
213 if FormatCSV then begin
214 WriteRaw(TimeStr + ',' +
215 FloatToStrF((LineTime - LastLineTime) / OneSecond, ffFixed, 10, 2) + ',"');
216 end else begin
217 if UseEscapeChars then
218 WriteRaw(#$1b'[0;32m' + TimeStr + #$1b'[0m ')
219 else WriteRaw(TimeStr + ' ');
220 end;
221 WriteLog(TimeStr + ' ');
222 LastLineTime := LineTime;
223 Sleep(Trunc(TestLineDelay / OneMillisecond));
224end;
225
226procedure TMyApplication.ProcessBuffer(Buffer: string);
227var
228 P: Integer;
229 I: Integer;
230 Part: string;
231 FoundLineEnding: string;
232begin
233 NewLineEnding := LineEnding;
234 repeat
235 FoundLineEnding := '';
236 P := FindLineEnding(Buffer, FoundLineEnding);
237 if P > 0 then begin
238 Part := Copy(Buffer, 1, P - 1);
239 if FormatCSV then
240 Part := StringReplace(Part, '"', '""', [rfReplaceAll]);
241 PrintOutput(Part);
242 NewLineEnding := FoundLineEnding;
243 Delete(Buffer, 1, P - 1 + Length(FoundLineEnding));
244 NewLine := True;
245 ShowTime := True;
246 end;
247
248 until P = 0;
249 PrintOutput(Buffer);
250end;
251
252constructor TMyApplication.Create(TheOwner: TComponent);
253begin
254 inherited Create(TheOwner);
255 StopOnException := True;
256 TestLineDelay := 0;
257 TestMode := False;
258 //TestMode := True;
259 if TestMode then begin
260 TestLineDelay := 10 * OneMillisecond;
261 //TestString := 'Line 1'#13#10'Line 2'#13'Line 3'#10'Line 4 abcd abcd xyz'#13#10#13#10'Line 9'#13#13#10'Line 10';
262 TestString := 'sas'#13#13#10'Line 10';
263 end;
264end;
265
266destructor TMyApplication.Destroy;
267begin
268 FreeAndNil(LogFile);
269 inherited Destroy;
270end;
271
272procedure TMyApplication.WriteHelp;
273begin
274 WriteLn('Usage: ', ExeName, ' <parameters>');
275 WriteLn(' -h --help Show this help');
276 WriteLn(' -c --csv Print lines in CSV format');
277 WriteLn(' -l --log Log output to log files in ~/.linetime/logs');
278 WriteLn(' -t --termstr <string> Termination string');
279 WriteLn(' -e --escape Use escape characters for color change');
280end;
281
282var
283 Application: TMyApplication;
284begin
285 Application := TMyApplication.Create(nil);
286 Application.Run;
287 Application.Free;
288end.
289
Note: See TracBrowser for help on using the repository browser.