* ppudump: Started implementation of JSON output. Output of unit header info has been implemented.

git-svn-id: trunk@24299 -
This commit is contained in:
yury 2013-04-22 14:08:53 +00:00
parent 6327854259
commit 85c2d144c5
4 changed files with 750 additions and 13 deletions

2
.gitattributes vendored
View File

@ -691,6 +691,8 @@ compiler/utils/msg2inc.pp svneol=native#text/plain
compiler/utils/msgdif.pp svneol=native#text/plain
compiler/utils/msgused.pl svneol=native#text/plain
compiler/utils/ppudump/ppudump.pp svneol=native#text/plain
compiler/utils/ppudump/ppujson.pp svneol=native#text/plain
compiler/utils/ppudump/ppuout.pp svneol=native#text/plain
compiler/utils/ppufiles.pp svneol=native#text/plain
compiler/utils/ppumove.pp svneol=native#text/plain
compiler/utils/samplecfg svneol=native#text/plain

View File

@ -35,7 +35,9 @@ uses
globals,
globtype,
widestr,
tokens;
tokens,
ppuout,
ppujson;
const
Version = 'Version 2.7.1';
@ -185,6 +187,10 @@ var
verbose : longint;
derefdata : pbyte;
derefdatalen : longint;
pout: TPpuOutput;
nostdout: boolean;
UnitList: TPpuContainerDef;
CurUnit: TPpuUnitDef;
{****************************************************************************
@ -277,6 +283,7 @@ const has_errors : boolean = false;
procedure Write(const s: string);
begin
if nostdout then exit;
system.write(s);
end;
@ -284,6 +291,7 @@ procedure Write(const params: array of const);
var
i: integer;
begin
if nostdout then exit;
for i:=Low(params) to High(params) do
with TVarRec(params[i]) do
case VType of
@ -305,11 +313,13 @@ end;
procedure Writeln(const s: string = '');
begin
if nostdout then exit;
system.writeln(s);
end;
procedure Writeln(const params: array of const);
begin
if nostdout then exit;
Write(params);
system.writeln;
end;
@ -674,14 +684,19 @@ end;
procedure ReadLoadUnit;
var
ucrc,uintfcrc, indcrc : cardinal;
un: TPpuUnitDef;
begin
while not ppufile.EndOfEntry do
begin
write(['Uses unit: ',ppufile.getstring]);
un:=TPpuUnitDef.Create(CurUnit.UsedUnits);
un.Name:=ppufile.getstring;
write(['Uses unit: ',un.Name]);
ucrc:=cardinal(ppufile.getlongint);
uintfcrc:=cardinal(ppufile.getlongint);
indcrc:=cardinal(ppufile.getlongint);
writeln([' (Crc: ',hexstr(ucrc,8),', IntfcCrc: ',hexstr(uintfcrc,8),', IndCrc: ',hexstr(indcrc,8),')']);
un.Crc:=ucrc;
un.IntfCrc:=uintfcrc;
end;
end;
@ -692,8 +707,12 @@ var
begin
mapsize:=ppufile.getlongint;
writeln(['DerefMapsize: ',mapsize]);
SetLength(CurUnit.RefUnits, mapsize);
for i:=0 to mapsize-1 do
writeln(['DerefMap[',i,'] = ',ppufile.getstring]);
begin
CurUnit.RefUnits[i]:=ppufile.getstring;
writeln(['DerefMap[',i,'] = ',CurUnit.RefUnits[i]]);
end;
end;
@ -2797,7 +2816,7 @@ end;
procedure readinterface;
var
b : byte;
sourcenumber : longint;
sourcenumber, i : longint;
begin
with ppufile do
begin
@ -2806,7 +2825,10 @@ begin
case b of
ibmodulename :
Writeln(['Module Name: ',getstring]);
begin
CurUnit.Name:=getstring;
Writeln(['Module Name: ',CurUnit.Name]);
end;
ibmoduleoptions:
readmoduleoptions(' ');
@ -2816,7 +2838,14 @@ begin
sourcenumber:=1;
while not EndOfEntry do
begin
Writeln(['Source file ',sourcenumber,' : ',getstring,' ',filetimestring(getlongint)]);
with TPpuSrcFile.Create(CurUnit.SourceFiles) do begin
Name:=getstring;
i:=getlongint;
if i >= 0 then
FileTime:=FileDateToDateTime(i);
Writeln(['Source file ',sourcenumber,' : ',Name,' ',filetimestring(i)]);
end;
inc(sourcenumber);
end;
end;
@ -2969,6 +2998,10 @@ begin
SetHasErrors;
exit;
end;
CurUnit:=TPpuUnitDef.Create(UnitList);
CurUnit.Version:=ppuversion;
{ Write PPU Header Information }
if (verbose and v_header)<>0 then
begin
@ -2991,6 +3024,15 @@ begin
Writeln(['Symbols stored : ',tostr(symlistsize)]);
end;
end;
with ppufile.header do
begin
CurUnit.Crc:=checksum;
CurUnit.IntfCrc:=interface_checksum;
CurUnit.TargetCPU:=Cpu2Str(cpu);
CurUnit.TargetOS:=Target2Str(target);
end;
{read the general stuff}
if (verbose and v_interface)<>0 then
begin
@ -3097,13 +3139,20 @@ begin
Writeln;
end;
procedure WriteLogo;
begin
writeln(Title+' '+Version);
writeln(Copyright);
writeln;
end;
procedure help;
begin
WriteLogo;
writeln('usage: ppudump [options] <filename1> <filename2>...');
writeln;
writeln('[options] can be:');
writeln(' -J output in JSON format');
writeln(' -M Exit with ExitCode=2 if more information is available');
writeln(' -V<verbose> Set verbosity to <verbose>');
writeln(' H - Show header info');
@ -3124,11 +3173,9 @@ var
const
error_on_more : boolean = false;
begin
writeln(Title+' '+Version);
writeln(Copyright);
writeln;
if paramcount<1 then
begin
WriteLogo;
writeln('usage: dumpppu [options] <filename1> <filename2>...');
halt(1);
end;
@ -3140,6 +3187,10 @@ begin
begin
para:=paramstr(startpara);
case upcase(para[2]) of
'J' : begin
nostdout:=True;
pout:=TPpuJsonOutput.Create(Output);
end;
'M' : error_on_more:=true;
'V' : begin
verbose:=0;
@ -3158,9 +3209,21 @@ begin
end;
inc(startpara);
end;
{ process files }
for nrfile:=startpara to paramcount do
dofile (paramstr(nrfile));
if not nostdout then
WriteLogo;
UnitList:=TPpuContainerDef.Create(nil);
try
{ process files }
for nrfile:=startpara to paramcount do
dofile (paramstr(nrfile));
if not has_errors and (pout <> nil) then
UnitList.Write(pout);
finally
UnitList.Free;
pout.Free;
end;
if has_errors then
Halt(1);
if error_on_more and has_more_infos then

View File

@ -0,0 +1,267 @@
{
Copyright (c) 2013 by Yury Sidorov and the FPC Development Team
JSON output of a PPU File
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************}
unit ppujson;
{$mode objfpc}{$H+}
interface
uses
SysUtils, Classes, ppuout;
type
{ TPpuJsonOutput }
TPpuJsonOutput = class(TPpuOutput)
private
FNeedDelim: array of boolean;
function JsonStr(const s: string): string;
procedure BeforeWriteElement;
procedure WriteAttr(const AName, AValue: string);
protected
procedure WriteDefStart(Def: TPpuDef); override;
procedure WriteDefEnd(Def: TPpuDef); override;
procedure WriteSubItemsStart(Def: TPpuContainerDef); override;
procedure WriteSubItemsEnd(Def: TPpuContainerDef); override;
procedure WriteArrayStart(const AName: string); override;
procedure WriteArrayEnd(const AName: string); override;
procedure WriteStr(const AName, AValue: string); override;
procedure WriteInt(const AName: string; AValue: Int64); override;
procedure WriteFloat(const AName: string; AValue: extended); override;
procedure WriteBool(const AName: string; AValue: boolean); override;
public
constructor Create(var OutFile: Text); override;
procedure IncI; override;
procedure DecI; override;
end;
implementation
{ TPpuJsonOutput }
function TPpuJsonOutput.JsonStr(const s: string): string;
var
ws: widestring;
ps: PWideChar;
pd: PAnsiChar;
i, slen, dlen, dpos: integer;
procedure _AddChar(c: ansichar);
begin
if dpos = dlen then begin
dlen:=dlen*2;
SetLength(Result, dlen);
pd:=PAnsiChar(Result) + dpos;
end;
pd^:=c;
Inc(pd);
Inc(dpos);
end;
var
c: widechar;
ss: shortstring;
begin
ws:=UTF8Decode(s);
ps:=PWideChar(ws);
slen:=Length(ws);
dlen:=slen + 2;
SetLength(Result, dlen);
pd:=PAnsiChar(Result);
dpos:=0;
_AddChar('"');
while slen > 0 do begin
c:=ps^;
case c of
'"', '\', '/':
begin
_AddChar('\');
_AddChar(c);
end;
#8:
begin
_AddChar('\');
_AddChar('b');
end;
#9:
begin
_AddChar('\');
_AddChar('t');
end;
#10:
begin
_AddChar('\');
_AddChar('n');
end;
#13:
begin
_AddChar('\');
_AddChar('r');
end;
#12:
begin
_AddChar('\');
_AddChar('f');
end;
else
if (c < #32) or (c > #127) then begin
_AddChar('\');
_AddChar('u');
ss:=hexStr(integer(c), 4);
for i:=1 to 4 do
_AddChar(ss[i]);
end
else
_AddChar(c);
end;
Inc(ps);
Dec(slen);
end;
_AddChar('"');
SetLength(Result, dpos);
end;
procedure TPpuJsonOutput.BeforeWriteElement;
begin
if FNeedDelim[Indent] then
WriteLn(',');
FNeedDelim[Indent]:=True;
end;
procedure TPpuJsonOutput.WriteAttr(const AName, AValue: string);
begin
BeforeWriteElement;
if AName <> '' then
Write(Format('"%s": %s', [AName, AValue]))
else
Write(AValue);
end;
procedure TPpuJsonOutput.WriteDefStart(Def: TPpuDef);
begin
if Def.Parent = nil then
// Top level container
exit;
WriteLn('{');
IncI;
if Def.DefType <> dtNone then
WriteStr('Type', Def.DefTypeName);
if Def.Name <> '' then
WriteStr('Name', Def.Name);
end;
procedure TPpuJsonOutput.WriteDefEnd(Def: TPpuDef);
var
s: string;
begin
if Def.Parent = nil then
// Top level container
exit;
DecI;
s:='}';
// Last def in list?
if (Def.Parent <> nil) and (Def.Parent[Def.Parent.Count - 1] <> Def) then
s:=s + ',';
WriteLn(s);
end;
procedure TPpuJsonOutput.WriteSubItemsStart(Def: TPpuContainerDef);
begin
if Def.Parent = nil then begin
// Top level container
WriteLn('[');
exit;
end;
BeforeWriteElement;
WriteLn(Format('"%s": [', [Def.ItemsName]));
end;
procedure TPpuJsonOutput.WriteSubItemsEnd(Def: TPpuContainerDef);
begin
Write(']');
if Def.Parent = nil then
// Top level container
WriteLn;
end;
procedure TPpuJsonOutput.WriteStr(const AName, AValue: string);
begin
WriteAttr(AName, JsonStr(AValue));
end;
procedure TPpuJsonOutput.WriteInt(const AName: string; AValue: Int64);
begin
WriteAttr(AName, IntToStr(AValue));
end;
procedure TPpuJsonOutput.WriteFloat(const AName: string; AValue: extended);
var
s: string;
begin
Str(AValue, s);
WriteAttr(AName, s);
end;
procedure TPpuJsonOutput.WriteBool(const AName: string; AValue: boolean);
begin
if AValue then
WriteAttr(AName, 'true')
else
WriteAttr(AName, 'false');
end;
procedure TPpuJsonOutput.WriteArrayStart(const AName: string);
begin
BeforeWriteElement;
WriteLn(Format('"%s": [', [AName]));
IncI;
end;
procedure TPpuJsonOutput.WriteArrayEnd(const AName: string);
begin
DecI;
Write(']');
end;
constructor TPpuJsonOutput.Create(var OutFile: Text);
begin
inherited Create(OutFile);
SetLength(FNeedDelim, 10);
FNeedDelim[0]:=False;
end;
procedure TPpuJsonOutput.IncI;
begin
inherited IncI;
if Length(FNeedDelim) >= Indent then
SetLength(FNeedDelim, Indent + 1);
FNeedDelim[Indent]:=False;
end;
procedure TPpuJsonOutput.DecI;
begin
if FNeedDelim[Indent] then
WriteLn;
inherited DecI;
end;
end.

View File

@ -0,0 +1,405 @@
{
Copyright (c) 2013 by Yury Sidorov and the FPC Development Team
Base classes for a custom output of a PPU File
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************}
unit ppuout;
{$mode objfpc}{$H+}
interface
uses SysUtils, Classes;
type
TPpuDefType = (dtNone, dtUnit, dtClass, dtRecord, dtProc, dtField, dtProp, dtParam, dtVar,
dtType, dtConst, dtProcType, dtEnum, dtSet);
TPpuDef = class;
TPpuContainerDef = class;
{ TPpuOutput }
TPpuOutput = class
private
FOutFile: ^Text;
FIndent: integer;
FIndentSize: integer;
FIndStr: string;
FNoIndent: boolean;
procedure SetIndent(AValue: integer);
procedure SetIndentSize(AValue: integer);
protected
procedure WriteDefStart(Def: TPpuDef); virtual;
procedure WriteDefEnd(Def: TPpuDef); virtual;
procedure WriteSubItemsStart(Def: TPpuContainerDef); virtual;
procedure WriteSubItemsEnd(Def: TPpuContainerDef); virtual;
procedure WriteStr(const AName, AValue: string); virtual;
procedure WriteInt(const AName: string; AValue: Int64); virtual;
procedure WriteFloat(const AName: string; AValue: extended); virtual;
procedure WriteBool(const AName: string; AValue: boolean); virtual;
procedure WriteArrayStart(const AName: string); virtual;
procedure WriteArrayEnd(const AName: string); virtual;
public
constructor Create(var OutFile: Text); virtual;
destructor Destroy; override;
procedure Write(const s: string);
procedure WriteLn(const s: string = '');
procedure IncI; virtual;
procedure DecI; virtual;
property Indent: integer read FIndent write SetIndent;
property IndentSize: integer read FIndentSize write SetIndentSize;
end;
{ TPpuDef }
TPpuDef = class
private
FParent: TPpuContainerDef;
function GetDefTypeName: string;
procedure SetProps(AValue: TStringList);
protected
procedure WriteDef(Output: TPpuOutput); virtual;
public
DefType: TPpuDefType;
Name: string;
DefId: integer;
constructor Create(AParent: TPpuContainerDef); virtual; reintroduce;
destructor Destroy; override;
procedure Write(Output: TPpuOutput);
property Parent: TPpuContainerDef read FParent;
property DefTypeName: string read GetDefTypeName;
end;
{ TPpuContainerDef }
TPpuContainerDef = class(TPpuDef)
private
FItems: TList;
function GetCount: integer;
function GetItem(Index: Integer): TPpuDef;
procedure SetItem(Index: Integer; AValue: TPpuDef);
protected
procedure WriteDef(Output: TPpuOutput); override;
public
ItemsName: string;
constructor Create(AParent: TPpuContainerDef); override;
destructor Destroy; override;
function Add(Def: TPpuDef): integer;
property Items[Index: Integer]: TPpuDef read GetItem write SetItem; default;
property Count: integer read GetCount;
end;
{ TPpuUnitDef }
TPpuUnitDef = class(TPpuContainerDef)
protected
procedure WriteDef(Output: TPpuOutput); override;
public
Version: cardinal;
Crc, IntfCrc: cardinal;
TargetOS, TargetCPU: string;
UsedUnits: TPpuContainerDef;
RefUnits: array of string;
SourceFiles: TPpuContainerDef;
constructor Create(AParent: TPpuContainerDef); override;
destructor Destroy; override;
end;
{ TPpuSrcFile }
TPpuSrcFile = class(TPpuDef)
protected
procedure WriteDef(Output: TPpuOutput); override;
public
FileTime: TDateTime;
end;
implementation
const
DefTypeNames: array[TPpuDefType] of string =
('', 'unit', 'class', 'record', 'procedure', 'field', 'property', 'parameter', 'variable',
'type', 'constant', 'proctype', 'enum', 'set');
{ TPpuSrcFile }
procedure TPpuSrcFile.WriteDef(Output: TPpuOutput);
begin
inherited WriteDef(Output);
Output.WriteStr('Time', FormatDateTime('yyyy"-"mm"-"dd hh":"nn":"ss', FileTime));
end;
{ TPpuOutput }
procedure TPpuOutput.SetIndent(AValue: integer);
begin
if FIndent=AValue then Exit;
FIndent:=AValue;
if FIndent < 0 then
FIndent:=0;
SetLength(FIndStr, FIndent*IndentSize);
if FIndent > 0 then
FillChar(FIndStr[1], FIndent*IndentSize, ' ');
end;
procedure TPpuOutput.SetIndentSize(AValue: integer);
begin
if FIndentSize=AValue then Exit;
FIndentSize:=AValue;
end;
procedure TPpuOutput.WriteDefStart(Def: TPpuDef);
begin
end;
procedure TPpuOutput.WriteDefEnd(Def: TPpuDef);
begin
end;
procedure TPpuOutput.WriteSubItemsStart(Def: TPpuContainerDef);
begin
end;
procedure TPpuOutput.WriteSubItemsEnd(Def: TPpuContainerDef);
begin
end;
procedure TPpuOutput.WriteStr(const AName, AValue: string);
begin
end;
procedure TPpuOutput.WriteInt(const AName: string; AValue: Int64);
begin
WriteStr(AName, IntToStr(AValue));
end;
procedure TPpuOutput.WriteFloat(const AName: string; AValue: extended);
var
s: string;
begin
Str(AValue, s);
WriteStr(AName, s);
end;
procedure TPpuOutput.WriteBool(const AName: string; AValue: boolean);
var
s: string;
begin
if AValue then
s:='1'
else
s:='0';
WriteStr(AName, s);
end;
procedure TPpuOutput.WriteArrayStart(const AName: string);
begin
end;
procedure TPpuOutput.WriteArrayEnd(const AName: string);
begin
end;
constructor TPpuOutput.Create(var OutFile: Text);
begin
FOutFile:=@OutFile;
FIndentSize:=2;
end;
destructor TPpuOutput.Destroy;
begin
inherited Destroy;
end;
procedure TPpuOutput.Write(const s: string);
begin
if not FNoIndent then
System.Write(FOutFile^, FIndStr);
System.Write(FOutFile^, s);
FNoIndent:=True;
end;
procedure TPpuOutput.WriteLn(const s: string);
begin
Self.Write(s + LineEnding);
FNoIndent:=False;
end;
procedure TPpuOutput.IncI;
begin
Indent:=Indent + 1;
end;
procedure TPpuOutput.DecI;
begin
Indent:=Indent - 1;
end;
{ TPpuUnitDef }
procedure TPpuUnitDef.WriteDef(Output: TPpuOutput);
var
i: integer;
begin
with Output do begin
if Version <> 0 then
WriteInt('Version', Version);
if TargetCPU <> '' then
WriteStr('TargetCPU', TargetCPU);
if TargetOS <> '' then
WriteStr('TargetOS', TargetOS);
if Crc <> 0 then
WriteStr('Crc', hexStr(Crc, 8));
if IntfCrc <> 0 then
WriteStr('InterfaceCrc', hexStr(IntfCrc, 8));
UsedUnits.WriteDef(Output);
if Length(RefUnits) > 0 then begin
WriteArrayStart('RefUnits');
for i:=0 to High(RefUnits) do
WriteStr('', RefUnits[i]);
WriteArrayEnd('RefUnits');
end;
SourceFiles.WriteDef(Output);
end;
inherited WriteDef(Output);
end;
constructor TPpuUnitDef.Create(AParent: TPpuContainerDef);
begin
inherited Create(AParent);
DefType:=dtUnit;
UsedUnits:=TPpuContainerDef.Create(nil);
UsedUnits.FParent:=Self;
UsedUnits.ItemsName:='UsedUnits';
SourceFiles:=TPpuContainerDef.Create(nil);
SourceFiles.FParent:=Self;
SourceFiles.ItemsName:='SrcFiles';
end;
destructor TPpuUnitDef.Destroy;
begin
UsedUnits.Free;
SourceFiles.Free;
inherited Destroy;
end;
{ TPpuContainerDef }
function TPpuContainerDef.GetCount: integer;
begin
Result:=FItems.Count;
end;
function TPpuContainerDef.GetItem(Index: Integer): TPpuDef;
begin
Result:=TPpuDef(FItems[Index]);
end;
procedure TPpuContainerDef.SetItem(Index: Integer; AValue: TPpuDef);
begin
FItems[Index]:=AValue;
end;
procedure TPpuContainerDef.WriteDef(Output: TPpuOutput);
var
i: integer;
begin
inherited WriteDef(Output);
if Count = 0 then
exit;
Output.WriteSubItemsStart(Self);
if Parent <> nil then
Output.IncI;
for i:=0 to Count - 1 do
Items[i].Write(Output);
if Parent <> nil then
Output.DecI;
Output.WriteSubItemsEnd(Self);
end;
constructor TPpuContainerDef.Create(AParent: TPpuContainerDef);
begin
inherited Create(AParent);
FItems:=TList.Create;
ItemsName:='Contents';
end;
destructor TPpuContainerDef.Destroy;
var
i: integer;
begin
for i:=0 to FItems.Count - 1 do
TObject(FItems[i]).Free;
FItems.Free;
inherited Destroy;
end;
function TPpuContainerDef.Add(Def: TPpuDef): integer;
begin
Result:=FItems.Add(Def);
Def.FParent:=Self;
end;
{ TPpuDef }
function TPpuDef.GetDefTypeName: string;
begin
Result:=DefTypeNames[DefType];
end;
procedure TPpuDef.SetProps(AValue: TStringList);
begin
end;
procedure TPpuDef.WriteDef(Output: TPpuOutput);
begin
with Output do begin
if DefId >= 0 then
WriteInt('Id', DefId);
end;
end;
constructor TPpuDef.Create(AParent: TPpuContainerDef);
begin
DefId:=-1;
if AParent <> nil then
AParent.Add(Self);
end;
destructor TPpuDef.Destroy;
begin
inherited Destroy;
end;
procedure TPpuDef.Write(Output: TPpuOutput);
begin
Output.WriteDefStart(Self);
WriteDef(Output);
Output.WriteDefEnd(Self);
end;
end.