{$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:=''; 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 j0) 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=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 (i2 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.