Componentes.Terceros.jvcl/official/3.32/devtools/UnitVersioning/Main.pas

329 lines
10 KiB
ObjectPascal
Raw Normal View History

unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, XPMan, Mask, JvExMask, JvToolEdit, ComCtrls,
JvComponent, JvSearchFiles, dpp_PascalParser;
type
TFormMain = class(TForm)
BtnExecute: TButton;
BtnQuit: TButton;
ProgressBar: TProgressBar;
DEditDir: TJvDirectoryEdit;
XPManifest1: TXPManifest;
JvSearchFiles: TJvSearchFiles;
CheckBoxSubDirs: TCheckBox;
EditLogPath: TEdit;
Label1: TLabel;
procedure BtnQuitClick(Sender: TObject);
procedure BtnExecuteClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private-Deklarationen }
procedure ProcessFile(const Filename: string);
function ParseUses(Parser: TPascalParser): Boolean;
public
{ Public-Deklarationen }
end;
var
FormMain: TFormMain;
implementation
uses
StrUtils;
{$R *.dfm}
var
ConditionStack: TStrings;
IsUseJVCL: Boolean;
procedure TFormMain.BtnQuitClick(Sender: TObject);
begin
Close;
end;
procedure TFormMain.BtnExecuteClick(Sender: TObject);
var
Dir: string;
i: Integer;
begin
Dir := DEditDir.Text;
BtnExecute.Enabled := False;
try
JvSearchFiles.RootDirectory := Dir;
if CheckBoxSubDirs.Checked then
JvSearchFiles.DirOption := doIncludeSubDirs
else
JvSearchFiles.DirOption := doExcludeSubDirs;
if JvSearchFiles.Search then
begin
ProgressBar.Position := 0;
ProgressBar.Max := JvSearchFiles.Files.Count;
for i := 0 to JvSearchFiles.Files.Count - 1 do
begin
if Pos('\cvs\', AnsiLowerCase(JvSearchFiles.Files[i])) = 0 then
ProcessFile(JvSearchFiles.Files[i]);
ProgressBar.StepIt;
Application.ProcessMessages;
end;
end;
finally
BtnExecute.Enabled := True;
end;
end;
function NextToken(Parser: TPascalParser; out Token: PTokenInfo): Boolean;
begin
Result := True;
while Parser.GetToken(Token) do
begin
if Token.Kind <> tkComment then
Exit
else
begin
if Token.ExKind = tekOption then
begin
if AnsiStartsText('{$ENDIF', Token.Value) or AnsiStartsText('{$IFEND', Token.Value) then
begin
ConditionStack.Delete(ConditionStack.Count - 1);
end
else
if AnsiStartsText('{$IF', Token.Value) then
begin
ConditionStack.Add(Token.Value);
if Pos('USEJVCL', AnsiUpperCase(Token.Value)) > 0 then
IsUseJVCL := True;
end;
end;
end;
end;
Result := False;
end;
// returns True if the "JclUnitVersioning" unit is in the uses list
function TFormMain.ParseUses(Parser: TPascalParser): Boolean;
var
Token: PTokenInfo;
begin
Result := False;
while NextToken(Parser, Token) do
begin
case Token.Kind of
tkSymbol:
if Token.Value = ';' then
Break; // uses-end
tkIdent:
if CompareText(Token.Value, 'in') = 0 then
begin
if CompareText(Token.Value, 'JclUnitVersioning') = 0 then
begin
Result := True;
Exit;
end;
end;
//tkString: ;
end;
end;
end;
procedure TFormMain.ProcessFile(const Filename: string);
var
s: string;
Stream: TFileStream;
Token: PTokenInfo;
UsesToken, ImplToken, InitToken, FiniToken, LastEndToken: TTokenInfo;
Parser: TPascalParser;
InImplementation: Boolean;
Modified, HasImplUses, HasInit, HasFini: Boolean;
sl: TStrings;
ConstDecl: string;
begin
Modified := False;
IsUseJVCL := False;
Stream := TFileStream.Create(Filename, fmOpenReadWrite or fmShareExclusive);
ConditionStack := TStringList.Create;
try
SetLength(s, Stream.Size);
Stream.Read(s[1], Length(s));
Parser := TPascalParser.Create('', s);
try
s := ''; // release memory
FillChar(ImplToken, 0, SizeOf(ImplToken));
FillChar(LastEndToken, 0, SizeOf(LastEndToken));
HasInit := False;
HasFini := False;
HasImplUses := False;
InImplementation := False;
while NextToken(Parser, Token) do
begin
if Token.Kind = tkIdent then
begin
if CompareText(Token.Value, 'implementation') = 0 then
begin
ImplToken := Token^;
InImplementation := True;
end
else if InImplementation then
begin
if CompareText(Token.Value, 'uses') = 0 then
begin
HasImplUses := True;
UsesToken := Token^; // save
if not ParseUses(Parser) then
begin
Parser.Insert(UsesToken.EndIndex + 1,
sLineBreak +
' {$IFDEF UNITVERSIONING}' + sLineBreak +
' JclUnitVersioning,' + sLineBreak +
' {$ENDIF UNITVERSIONING}');
Parser.Index := UsesToken.EndIndex + 1;
Modified := True;
end;
end
else if CompareText(Token.Value, 'initialization') = 0 then
begin
HasInit := True;
InitToken := Token^;
if ConditionStack.Count > 0 then
ShowMessage('initialization is IFDEFed: ' + Filename);
end
else if CompareText(Token.Value, 'finalization') = 0 then
begin
HasFini := True;
FiniToken := Token^;
if ConditionStack.Count > 0 then
ShowMessage('finalization is IFDEFed: ' + Filename);
end
else if CompareText(Token.Value, 'end') = 0 then
LastEndToken := Token^;
end;
end;
end;
if not HasImplUses and InImplementation then
begin
Modified := True;
// do not change the text here because this would offset the index of
// InitToken and LastEndToken
end;
if Modified then
begin
ConstDecl :=
'const' + sLineBreak +
' UnitVersioning: TUnitVersionInfo = (' + sLineBreak +
' RCSfile: ''$' + 'RCSfile$'';' + sLineBreak +
' Revision: ''$' + 'Revision$'';' + sLineBreak +
' Date: ''$' + 'Date$'';' + sLineBreak +
' LogPath: ''' + Trim(EditLogPath.Text) + '''' + sLineBreak +
' );' + sLineBreak;
if not HasInit then
begin
if LastEndToken.StartIndex = 0 then
raise Exception.CreateFmt('Invalid .pas file: %s', [Filename]);
Parser.Insert(LastEndToken.StartIndex,
'{$IFDEF UNITVERSIONING}' + sLineBreak +
ConstDecl +
sLineBreak +
'initialization' + sLineBreak +
' RegisterUnitVersion(HInstance, UnitVersioning);' + sLineBreak +
sLineBreak +
'finalization' + sLineBreak +
' UnregisterUnitVersion(HInstance);' + sLineBreak +
'{$ENDIF UNITVERSIONING}' + sLineBreak +
sLineBreak);
end
else
begin
if not HasFini then
begin
if LastEndToken.StartIndex = 0 then
raise Exception.CreateFmt('Invalid .pas file: %s', [Filename]);
Parser.Insert(LastEndToken.StartIndex,
sLineBreak +
'{$IFDEF UNITVERSIONING}' + sLineBreak +
'finalization' + sLineBreak +
' UnregisterUnitVersion(HInstance);' + sLineBreak +
'{$ENDIF UNITVERSIONING}' + sLineBreak +
sLineBreak);
end
else
begin
Parser.Insert(FiniToken.EndIndex + 1,
sLineBreak +
' {$IFDEF UNITVERSIONING}' + sLineBreak +
' UnregisterUnitVersion(HInstance);' + sLineBreak +
' {$ENDIF UNITVERSIONING}');
end;
Parser.Insert(InitToken.EndIndex + 1,
sLineBreak +
' {$IFDEF UNITVERSIONING}' + sLineBreak +
' RegisterUnitVersion(HInstance, UnitVersioning);' + sLineBreak +
' {$ENDIF UNITVERSIONING}' + sLineBreak);
Parser.Insert(InitToken.StartIndex,
'{$IFDEF UNITVERSIONING}' + sLineBreak +
ConstDecl +
'{$ENDIF UNITVERSIONING}' + sLineBreak +
sLineBreak);
end;
end;
if not HasImplUses and InImplementation then
begin
Parser.Insert(ImplToken.EndIndex + 1,
sLineBreak +
sLineBreak +
'{$IFDEF UNITVERSIONING}' + sLineBreak +
'uses' + sLineBreak +
' JclUnitVersioning;' + sLineBreak +
'{$ENDIF UNITVERSIONING}');
if IsUseJVCL then
begin
Parser.Insert(ImplToken.StartIndex,
'{$IFNDEF USEJVCL}' + sLineBreak +
' {$UNDEF UNITVERSIONING}' + sLineBreak +
'{$ENDIF ~USEJVCL}' + sLineBreak +
sLineBreak);
end;
end;
if Modified then
begin
sl := TStringList.Create;
sl.Text := Parser.Text;
sl.SaveToFile(ExtractFilePath(Filename) + '\new\' + ExtractFileName(Filename));
sl.Free;
{Stream.Position := 0;
Stream.Size := 0; // truncate
Stream.Write(Parser.Text[1], Length(Parser.Text));}
end;
finally
Parser.Free;
end;
finally
FreeAndNil(ConditionStack);
Stream.Free;
end;
end;
procedure TFormMain.FormCreate(Sender: TObject);
begin
DEditDir.Text := ExtractFileDir(ExtractFileDir(ExtractFileDir(ParamStr(0)))) + PathDelim + 'run';
end;
end.