-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtail.pas
115 lines (100 loc) · 3.08 KB
/
tail.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
{ --------------------------------------------------------------------------
godaemon
Tail unit (read files backwards)
Copyright (c) Michael Nixon 2015.
Please see the LICENSE file for licensing information.
-------------------------------------------------------------------------- }
{ --------------------------------------------------------------------------
-------------------------------------------------------------------------- }
unit tail;
interface
uses baseunix, unix, unixutil, sockets, sysutils, classes, logger;
{ Non-class functions and procedures }
function TailFile(filename: ansistring; lines: longint): tstringlist;
{ --------------------------------------------------------------------------
-------------------------------------------------------------------------- }
implementation
uses settings, strutils, process, btime;
{ --------------------------------------------------------------------------
Return the last <lines> lines from the file <filename>.
Returns a tstringlist containing the lines, or nil if the file could not
be opened or could not be read properly.
-------------------------------------------------------------------------- }
function TailFile(filename: ansistring; lines: longint): tstringlist;
const
maxlinelength = 8192;
var
handle: file;
strings: tstringlist;
endpos: longint;
count: longint;
readbuffer: array[0..maxlinelength - 1] of byte;
readpos: longint;
readcount: longint;
scan: longint;
linefound: boolean;
s: ansistring;
linelen: longint;
begin
try
filemode := fmOpenRead;
assignfile(handle, filename);
reset(handle, 1);
except
on e: exception do begin
result := nil;
exit;
end;
end;
strings := tstringlist.create;
endpos := filesize(handle);
for count := 1 to lines do begin
{ Get next block }
readpos := endpos - maxlinelength;
if readpos < 0 then begin
readpos := 0;
readcount := endpos;
end else begin
readcount := maxlinelength;
end;
seek(handle, readpos);
blockread(handle, readbuffer[0], readcount);
{ Scan backwards for linefeed }
linefound := false;
for scan := readcount - 1 downto 0 do begin
if readbuffer[scan] = 10 then begin
{ Line found }
linefound := true;
linelen := readcount - scan;
if linelen > 1 then begin
{ Skip LF }
setlength(s, linelen - 1);
move(readbuffer[scan + 1], s[1], linelen - 1);
strings.Add(s);
end else begin
{ Empty line }
//strings.Add('');
end;
dec(endpos, linelen);
break;
end;
end;
{ Abort if line is too long or no more lines in file }
if not linefound then begin
if readcount < maxlinelength then begin
{ No more lines so grab the last }
setlength(s, readcount);
move(readbuffer[0], s[1], readcount);
strings.Add(s);
result := strings;
end else begin
result := nil;
end;
closefile(handle);
exit;
end;
end;
closefile(handle);
result := strings;
end;
end.