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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
{$mode objfpc}
{$h+}
uses
sysutils,classes,dom,xmlread;
procedure error(const s : string);
begin
writeln('Error: ',s);
halt(1);
end;
var
doc : txmldocument;
root : TDomNode;
entry,
currentpath,
currentinfo : TDomNode;
hs,
dirprefix,
newlineprefix,
currentmsg,
currentauthor,
currentdate,
pathtemp,
currentrevision : string;
paths : tstringlist;
pathprefixes : tstringlist;
i,j,maxequal : integer;
firstpath : boolean;
begin
paths:=tstringlist.create;
paths.sorted:=true;
pathprefixes:=tstringlist.create;
pathprefixes.sorted:=true;
ReadXMLFile(doc,paramstr(1));
root:=doc.DocumentElement;
if root.haschildnodes and
(root.NodeName='log') then
begin
entry:=root.firstchild;
while assigned(entry) do
begin
if entry.NodeName<>'logentry' then
error('Only log entry entries supported, but '+entry.NodeName+' found.');
currentmsg:='';
currentauthor:='';
currentdate:='';
{ get revision }
with entry as tdomelement do
currentrevision:=AttribStrings['revision'];
if entry.haschildnodes then
begin
currentinfo:=entry.firstchild;
while assigned(currentinfo) do
begin
if currentinfo.NodeName='author' then
begin
if currentinfo.haschildnodes and
(currentinfo.firstchild is TDOMText) then
currentauthor:=(currentinfo.firstchild as TDOMText).Data
else
error('Malformed author node');
end
else if currentinfo.NodeName='msg' then
begin
if currentinfo.haschildnodes then
begin
if (currentinfo.firstchild is TDOMText) then
currentmsg:=(currentinfo.firstchild as TDOMText).Data
else
error('Malformed msg node');
end
else
currentmsg:='<empty log message>';
end
else if currentinfo.NodeName='date' then
begin
if currentinfo.haschildnodes and
(currentinfo.firstchild is TDOMText) then
currentdate:=(currentinfo.firstchild as TDOMText).Data
else
error('Malformed date node');
end
else if currentinfo.NodeName='paths' then
begin
currentpath:=currentinfo.firstchild;
paths.clear;
pathprefixes.clear;
while assigned(currentpath) do
begin
if currentpath.NodeName<>'path' then
error('Path node expected');
if currentpath.haschildnodes and
(currentpath.firstchild is TDOMText) then
begin
paths.add((currentpath.firstchild as TDOMText).Data);
hs:=ExtractFilePath((currentpath.firstchild as TDOMText).Data);
if not pathprefixes.Find(hs,i) then
pathprefixes.add(hs);
end
else
error('Malformed date node');
currentpath:=currentpath.NextSibling;
end;
end
else
error('Unknown logentry child '+currentinfo.NodeName+' found');
currentinfo:=currentinfo.nextsibling;
end;
currentdate:=copy(currentdate,1,16);
{ replaced T }
currentdate[11]:=' ';
write(currentdate,' ',currentauthor);
if currentrevision<>'' then
writeln(' r',currentrevision)
else
writeln;
writeln;
{ search for common pathprefix }
if pathprefixes.Count>1 then
begin
maxequal:=65535;
for i:=1 to pathprefixes.Count-1 do
begin
j:=1;
while (pathprefixes[0][j]=pathprefixes[i][j]) and (j<=maxequal) do
inc(j);
dec(j);
if j<maxequal then
maxequal:=j;
end;
{ test/p1.pas test/p2.pas should use the prefix test/ instead of test/p }
if maxequal<65535 then
while (maxequal>0) and (pathprefixes[0][maxequal]<>'/') do
dec(maxequal);
Writeln(' '+Copy(pathprefixes[0],1,maxequal)+': ');
dirprefix:=' ';
newlineprefix:=' ';
end
else
begin
maxequal:=0;
dirprefix:=' ';
newlineprefix:=' ';
end;
for i:=0 to pathprefixes.Count-1 do
begin
pathtemp:=dirprefix;
if maxequal+1<length(pathprefixes[i]) then
pathtemp:=pathtemp+Copy(pathprefixes[i],maxequal+1,65535)+': ';
firstpath:=true;
j:=0;
while (j<paths.Count) do
begin
if ExtractFilePath(paths[j])=pathprefixes[i] then
begin
hs:=copy(paths[j],length(pathprefixes[i])+1,65535);
if (length(pathtemp)+length(hs)>=78) and
(pathtemp<>newlineprefix) then
begin
writeln(pathtemp+',');
pathtemp:=newlineprefix;
firstpath:=true;
end;
{ non empty path but not first? }
if firstpath then
firstpath:=false
else
pathtemp:=pathtemp+', ';
pathtemp:=pathtemp+hs;
{ delete already processed paths for performance }
paths.delete(j);
end
else
inc(j);
end;
if pathtemp<>newlineprefix then
writeln(pathtemp);
end;
{ truncate trailing spaces and new lines from log message }
i:=length(currentmsg);
while (i>0) and (currentmsg[i] in [#13,#10,#9,' ']) do
dec(i);
delete(currentmsg,i+1,length(currentmsg)-i);
{ Pretty print message starting with at least 2 spaces each line }
writeln;
i:=0;
hs:=currentmsg;
while (hs<>'') do
begin
newlineprefix:=' ';
i:=0;
while (i<length(hs)) and not(hs[i+1] in [#13,#10]) do
inc(i);
j:=1;
while (j<length(hs)) and
(j<length(newlineprefix)) and
(hs[j] in [' ']) do
inc(j);
writeln(newlineprefix,copy(hs,j,i-j+1));
{ remove eol and add additional empty lines }
j:=0;
while (i<length(hs)) and (hs[i+1] in [#13,#10]) do
begin
if hs[i+1]=#10 then
begin
inc(j);
if j>2 then
writeln;
end;
inc(i);
end;
delete(hs,1,i);
end;
writeln;
end
else
error('Empty log entry found');
entry:=entry.nextsibling;
end;
end
else
error('log element not found/wrong xml format');
end.
|