mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-28 00:03:47 +02:00
4957 lines
148 KiB
ObjectPascal
4957 lines
148 KiB
ObjectPascal
{ Copyright (C) 2006 Mattias Gaertner
|
|
|
|
This source 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 code 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.
|
|
|
|
A copy of the GNU General Public License is available on the World Wide Web
|
|
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
|
|
to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
|
|
Boston, MA 02110-1335, USA.
|
|
|
|
}
|
|
unit H2PasConvert;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, AVL_Tree,
|
|
// LCL
|
|
LResources, Forms, Controls, Dialogs, XMLPropStorage,
|
|
// LazUtils
|
|
LazConfigStorage, FileUtil, LazFileUtils, LazFileCache, GraphMath,
|
|
// CodeTools
|
|
CodeAtom, CodeTree, KeywordFuncLists, NonPascalCodeTools, BasicCodeTools,
|
|
FileProcs, CodeCache, SourceChanger, CodeToolManager,
|
|
// IDEIntf
|
|
TextTools, IDEExternToolIntf, IDEDialogs, LazIDEIntf, SrcEditorIntf,
|
|
IDEMsgIntf, IDETextConverter,
|
|
// H2Pas
|
|
H2PasStrConsts;
|
|
|
|
type
|
|
|
|
{ TRemoveCPlusPlusExternCTool (for C header files)
|
|
Remove C++ 'extern "C"' lines }
|
|
|
|
TRemoveCPlusPlusExternCTool = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TRemoveEmptyCMacrosTool (for C header files)
|
|
Remove empty C macros}
|
|
|
|
TRemoveEmptyCMacrosTool = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TReplaceEdgedBracketPairWithStar (for C header files)
|
|
Replace [] with * }
|
|
|
|
TReplaceEdgedBracketPairWithStar = class(TCustomTextReplaceTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
constructor Create(TheOwner: TComponent); override;
|
|
end;
|
|
|
|
|
|
{ TReplaceMacro0PointerWithNULL (for C header files)
|
|
Replace macro values 0 pointer like (char *)0 with NULL }
|
|
|
|
TReplaceMacro0PointerWithNULL = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TConvertFunctionTypesToPointers (for C header files)
|
|
Replace function types with pointer to function type }
|
|
|
|
TConvertFunctionTypesToPointers = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TConvertEnumsToTypeDef (for C header files)
|
|
Give anoymous enums a name }
|
|
|
|
TConvertEnumsToTypeDef = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TCommentComplexCMacros (for C header files)
|
|
Comment macros that are too complex for h2pas }
|
|
|
|
TCommentComplexCMacros = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TCommentComplexCFunctions (for C header files)
|
|
Comment functions that are too complex for h2pas }
|
|
|
|
TCommentComplexCFunctions = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TAddMissingMacroBrackets (for C header files)
|
|
Add missing brackets around macro values }
|
|
|
|
TAddMissingMacroBrackets = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TReplaceUnitFilenameWithUnitName -
|
|
Replace "unit filename;" with "unit name;" }
|
|
|
|
TReplaceUnitFilenameWithUnitName = class(TCustomTextReplaceTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
constructor Create(TheOwner: TComponent); override;
|
|
end;
|
|
|
|
|
|
{ TRemoveIncludeDirectives - Remove all $i filename }
|
|
|
|
TRemoveIncludeDirectives = class(TCustomTextReplaceTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
constructor Create(TheOwner: TComponent); override;
|
|
end;
|
|
|
|
|
|
{ TRemoveDoubleSemicolons -
|
|
Remove double semicolons }
|
|
|
|
TRemoveDoubleSemicolons = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TRemoveSystemTypes -
|
|
Remove type redefinitions like PLongint }
|
|
|
|
TRemoveSystemTypes = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TRemoveRedefinedPointerTypes - Remove redefined pointer types }
|
|
|
|
TRemoveRedefinedPointerTypes = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TRemoveEmptyTypeVarConstSections - Remove empty type/var/const sections }
|
|
|
|
TRemoveEmptyTypeVarConstSections = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TReplaceImplicitTypes -
|
|
Search implicit types in parameters and add types for them
|
|
For example:
|
|
procedure ProcName(a: array[0..2] of char);
|
|
is replaced with
|
|
procedure ProcName(a: Tarray_0to2_of_char);
|
|
and a new type is added
|
|
Tarray_0to2_of_char = array[0..2] of char;
|
|
}
|
|
|
|
TReplaceImplicitTypes = class(TCustomTextConverterTool)
|
|
private
|
|
Src: String;
|
|
ImplicitTypes: TAVLTree;// tree of TImplicitType
|
|
ExplicitTypes: TAVLTree;// tree of TImplicitType
|
|
TypeStart: LongInt;
|
|
TypeEnd: integer; // 0 means invalid
|
|
ConstSectionStart: LongInt;
|
|
ConstSectionEnd: LongInt; // 0 means invalid
|
|
function FindNextImplicitType(var Position: integer;
|
|
out aTypeStart, aTypeEnd: integer): boolean;
|
|
function SearchImplicitParameterTypes(
|
|
var ModalResult: TModalResult): boolean;
|
|
function PosToStr(Position: integer): string;
|
|
procedure AdjustMinPositions(const Identifier: string);
|
|
function ReadWord(var Position: integer): boolean;
|
|
function ReadUntilAtom(var Position: integer;
|
|
const StopAtom: string; SkipBrackets: boolean = true): boolean;
|
|
function ReadRecord(var Position: integer): boolean;
|
|
function ReadClass(var Position: integer): boolean;
|
|
function ReadTypeDefinition(var Position: integer): boolean;
|
|
function ReadConstSection(var Position: integer): boolean;
|
|
function FindExplicitTypesAndConstants(
|
|
var ModalResult: TModalResult): boolean;
|
|
function InsertNewTypes(var ModalResult: TModalResult): boolean;
|
|
function FindInsertPosition(MinPos: integer): integer;
|
|
function UseNewTypes(var ModalResult: TModalResult): boolean;
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
function CodeToIdentifier(const Code: string): string;
|
|
end;
|
|
|
|
|
|
{ TFixArrayOfParameterType - Replace "array of )" with "array of const)" }
|
|
|
|
TFixArrayOfParameterType = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TRemoveRedefinitionsInUnit
|
|
Removes redefinitions of types, variables, constants and resourcestrings }
|
|
|
|
TRemoveRedefinitionsInUnit = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TAddMissingPointerTypes
|
|
Add missing pointer types like PPPChar }
|
|
|
|
TAddMissingPointerTypes = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TFixAliasDefinitionsInUnit - fix section type of alias definitions
|
|
|
|
Checks all alias definitions of the form
|
|
const LeftSide = RightSide;
|
|
looks up RightSide in the unit and if RightSide is a type or var, changes
|
|
the section accordingly }
|
|
|
|
TFixAliasDefinitionsInUnit = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TFixH2PasMissingIFDEFsInUnit - add missing IFDEFs for function bodies }
|
|
|
|
TFixH2PasMissingIFDEFsInUnit = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
|
|
{ TReduceCompilerDirectivesInUnit - removes unneeded directives }
|
|
|
|
TReduceCompilerDirectivesInUnit = class(TCustomTextConverterTool)
|
|
private
|
|
FDefines: TStrings;
|
|
FUndefines: TStrings;
|
|
procedure SetDefines(const AValue: TStrings);
|
|
procedure SetUndefines(const AValue: TStrings);
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
published
|
|
property Undefines: TStrings read FUndefines write SetUndefines;
|
|
property Defines: TStrings read FDefines write SetDefines;
|
|
end;
|
|
|
|
|
|
{ TReplaceConstFunctionsInUnit - replace simple assignment functions with constants }
|
|
|
|
TReplaceConstFunctionsInUnit = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
{ TReplaceTypeCastFunctionsInUnit - replace simple type cast functions with types }
|
|
|
|
TReplaceTypeCastFunctionsInUnit = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
{ TFixForwardDefinitions - reorder definitions }
|
|
|
|
TFixForwardDefinitions = class(TCustomTextConverterTool)
|
|
public
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
end;
|
|
|
|
{ TAddToUsesSection - add units to uses section }
|
|
|
|
TAddToUsesSection = class(TCustomTextConverterTool)
|
|
private
|
|
FUseUnits: TStrings;
|
|
procedure SetUseUnits(const AValue: TStrings);
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
published
|
|
property UseUnits: TStrings read FUseUnits write SetUseUnits;
|
|
end;
|
|
|
|
type
|
|
{ TPretH2PasTools - Combines the common tools. }
|
|
|
|
TPreH2PasToolsOption = (
|
|
phRemoveCPlusPlusExternCTool, // Remove C++ 'extern "C"' lines
|
|
phRemoveEmptyCMacrosTool, // Remove empty C macros
|
|
phReplaceEdgedBracketPairWithStar, // Replace [] with *
|
|
phReplaceMacro0PointerWithNULL, // Replace macro values 0 pointer like (char *)0
|
|
phConvertFunctionTypesToPointers, // Convert function types to pointers
|
|
phConvertEnumsToTypeDef, // Convert anonymous enums to ypedef enums
|
|
phCommentComplexCMacros, // Comment macros too complex for hpas
|
|
phCommentComplexCFunctions, // Comment functions too complex for hpas
|
|
phAddMissingMacroBrackets // Add missing macro brackets
|
|
);
|
|
TPreH2PasToolsOptions = set of TPreH2PasToolsOption;
|
|
const
|
|
DefaultPreH2PasToolsOptions =
|
|
[Low(TPreH2PasToolsOption)..High(TPreH2PasToolsOption)];
|
|
|
|
type
|
|
{ TPreH2PasTools }
|
|
|
|
TPreH2PasTools = class(TCustomTextConverterTool)
|
|
private
|
|
FOptions: TPreH2PasToolsOptions;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
published
|
|
property Options: TPreH2PasToolsOptions read FOptions write FOptions default DefaultPreH2PasToolsOptions;
|
|
end;
|
|
|
|
type
|
|
{ TPostH2PasTools - Combines the common tools. }
|
|
TPostH2PasToolsOption = (
|
|
phReplaceUnitFilenameWithUnitName, // Replace "unit filename;" with "unit name;"
|
|
phRemoveIncludeDirectives, // remove include directives
|
|
phRemoveDoubleSemicolons, // Remove double semicolons
|
|
phRemoveSystemTypes, // Remove type redefinitons like PLongint
|
|
phFixH2PasMissingIFDEFsInUnit, // add missing IFDEFs for function bodies
|
|
phReduceCompilerDirectivesInUnit, // removes unneeded directives
|
|
phRemoveRedefinedPointerTypes, // Remove redefined pointer types
|
|
phRemoveEmptyTypeVarConstSections, // Remove empty type/var/const sections
|
|
phReplaceImplicitTypes, // Search implicit types in parameters and add types for them
|
|
phFixArrayOfParameterType, // Replace "array of )" with "array of const)"
|
|
phAddMissingPointerTypes, // add missing pointer types
|
|
phRemoveRedefinitionsInUnit, // Removes redefinitions of types, variables, constants and resourcestrings
|
|
phFixAliasDefinitionsInUnit, // fix section type of alias definitions
|
|
phReplaceConstFunctionsInUnit, // replace simple assignment functions with constants
|
|
phReplaceTypeCastFunctionsInUnit, // replace simple type cast functions with types
|
|
phFixForwardDefinitions, // fix forward definitions by reordering
|
|
phAddUnitsToUsesSection // add units to uses section
|
|
);
|
|
TPostH2PasToolsOptions = set of TPostH2PasToolsOption;
|
|
const
|
|
DefaultPostH2PasToolsOptions =
|
|
[Low(TPostH2PasToolsOption)..High(TPostH2PasToolsOption)];
|
|
type
|
|
TPostH2PasTools = class(TCustomTextConverterTool)
|
|
private
|
|
FDefines: TStrings;
|
|
FOptions: TPostH2PasToolsOptions;
|
|
FUndefines: TStrings;
|
|
FUseUnits: TStrings;
|
|
procedure SetDefines(const AValue: TStrings);
|
|
procedure SetUndefines(const AValue: TStrings);
|
|
procedure SetUseUnits(const AValue: TStrings);
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
class function ClassDescription: string; override;
|
|
function Execute(aText: TIDETextConverter): TModalResult; override;
|
|
published
|
|
property Undefines: TStrings read FUndefines write SetUndefines;
|
|
property Defines: TStrings read FDefines write SetDefines;
|
|
property UseUnits: TStrings read FUseUnits write SetUseUnits;
|
|
property Options: TPostH2PasToolsOptions read FOptions write FOptions default DefaultPostH2PasToolsOptions;
|
|
end;
|
|
|
|
TH2PasFile = class;
|
|
|
|
{ TH2PasFileCInclude }
|
|
|
|
TH2PasFileCInclude = class
|
|
private
|
|
FFilename: string;
|
|
FH2PasFile: TH2PasFile;
|
|
FOwner: TH2PasFile;
|
|
FSrcFilename: string;
|
|
FSrcPos: TPoint;
|
|
procedure SetFilename(const AValue: string);
|
|
procedure SetH2PasFile(const AValue: TH2PasFile);
|
|
procedure SetSrcFilename(const AValue: string);
|
|
procedure SetSrcPos(const AValue: TPoint);
|
|
public
|
|
constructor Create(TheOwner: TH2PasFile);
|
|
destructor Destroy; override;
|
|
property Owner: TH2PasFile read FOwner;
|
|
property SrcFilename: string read FSrcFilename write SetSrcFilename;
|
|
property SrcPos: TPoint read FSrcPos write SetSrcPos;
|
|
property Filename: string read FFilename write SetFilename;
|
|
property H2PasFile: TH2PasFile read FH2PasFile write SetH2PasFile;
|
|
end;
|
|
|
|
TH2PasProject = class;
|
|
TH2PasConverter = class;
|
|
|
|
{ TH2PasFile }
|
|
|
|
TH2PasFile = class(TPersistent)
|
|
private
|
|
FCIncludes: TFPList; // list of TH2PasFileCInclude
|
|
FCIncludesValid: boolean;
|
|
FCIncludesFileAge: TDateTime;
|
|
FCIncludedBy: TFPList; // list of TH2PasFileCInclude
|
|
FEnabled: boolean;
|
|
FFilename: string;
|
|
FMerge: boolean;
|
|
FMergedBy: TH2PasFile;
|
|
FModified: boolean;
|
|
FProject: TH2PasProject;
|
|
function GetCIncludeCount: integer;
|
|
function GetCIncludedBy(Index: integer): TH2PasFileCInclude;
|
|
function GetCIncludedByCount: integer;
|
|
function GetCIncludes(Index: integer): TH2PasFileCInclude;
|
|
procedure SetEnabled(const AValue: boolean);
|
|
procedure SetFilename(const AValue: string);
|
|
procedure SetMerge(const AValue: boolean);
|
|
procedure SetModified(const AValue: boolean);
|
|
procedure SetProject(const AValue: TH2PasProject);
|
|
procedure SearchCIncFilenames;
|
|
procedure InternalAddCIncludedBy(CIncludedBy: TH2PasFileCInclude);
|
|
procedure InternalRemoveCIncludedBy(CIncludedBy: TH2PasFileCInclude);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
procedure ClearIncludedByReferences;
|
|
procedure ClearCIncludes;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function IsEqual(AFile: TH2PasFile): boolean;
|
|
procedure Load(Config: TConfigStorage);
|
|
procedure Save(Config: TConfigStorage);
|
|
function GetOutputFilename: string;
|
|
function GetOutputDirectory: string;
|
|
function GetOutputExtension: string;
|
|
function GetH2PasParameters(const InputFilename: string = ''): string;
|
|
function ReadCIncludes(ForceUpdate: boolean): TModalResult;
|
|
function CIncludesValid: boolean;
|
|
function FindCIncludedByWithOwner(ByOwner: TH2PasFile): TH2PasFileCInclude;
|
|
public
|
|
property Project: TH2PasProject read FProject write SetProject;
|
|
property Filename: string read FFilename write SetFilename;
|
|
property Enabled: boolean read FEnabled write SetEnabled;
|
|
property Modified: boolean read FModified write SetModified;
|
|
property CIncludeCount: integer read GetCIncludeCount;
|
|
property CIncludes[Index: integer]: TH2PasFileCInclude read GetCIncludes;
|
|
property CIncludedByCount: integer read GetCIncludedByCount;
|
|
property CIncludedBy[Index: integer]: TH2PasFileCInclude read GetCIncludedBy;
|
|
property Merge: boolean read FMerge write SetMerge;
|
|
property MergedBy: TH2PasFile read FMergedBy;// automatically chosen by the project
|
|
end;
|
|
|
|
{ TH2PasProject }
|
|
|
|
TH2PasProject = class(TPersistent)
|
|
private
|
|
FBaseDir: string;
|
|
FCHeaderFiles: TFPList;// list of TH2PasFile
|
|
FCompactOutputmode: boolean;
|
|
FConstantsInsteadOfEnums: boolean;
|
|
FConverter: TH2PasConverter;
|
|
FCreateIncludeFile: boolean;
|
|
FFilename: string;
|
|
FIsVirtual: boolean;
|
|
FLibname: string;
|
|
FModified: boolean;
|
|
FOutputDirectory: string;
|
|
FOutputExt: string;
|
|
FPackAllRecords: boolean;
|
|
FPalmOSSYSTrap: boolean;
|
|
FPforPointers: boolean;
|
|
FPostH2PasTools: TComponent;
|
|
FPreH2PasTools: TComponent;
|
|
FStripComments: boolean;
|
|
FStripCommentsAndInfo: boolean;
|
|
FTforTypedefs: boolean;
|
|
FTforTypedefsRemoveUnderscore: boolean;
|
|
FUseExternal: boolean;
|
|
FUseExternalLibname: boolean;
|
|
FUseProcVarsForImport: boolean;
|
|
FVarParams: boolean;
|
|
FWin32Header: boolean;
|
|
FUseCTypes : boolean;
|
|
function GetCHeaderFileCount: integer;
|
|
function GetCHeaderFiles(Index: integer): TH2PasFile;
|
|
procedure InternalAddCHeaderFile(AFile: TH2PasFile);
|
|
procedure InternalRemoveCHeaderFile(AFile: TH2PasFile);
|
|
procedure SetCompactOutputmode(const AValue: boolean);
|
|
procedure SetConstantsInsteadOfEnums(const AValue: boolean);
|
|
procedure SetCreateIncludeFile(const AValue: boolean);
|
|
procedure SetFilename(const AValue: string);
|
|
procedure SetLibname(const AValue: string);
|
|
procedure SetModified(const AValue: boolean);
|
|
procedure FilenameChanged;
|
|
procedure SetOutputDirectory(const AValue: string);
|
|
procedure SetOutputExt(const AValue: string);
|
|
procedure SetPackAllRecords(const AValue: boolean);
|
|
procedure SetPalmOSSYSTrap(const AValue: boolean);
|
|
procedure SetPforPointers(const AValue: boolean);
|
|
procedure SetStripComments(const AValue: boolean);
|
|
procedure SetStripCommentsAndInfo(const AValue: boolean);
|
|
procedure SetTforTypedefs(const AValue: boolean);
|
|
procedure SetTforTypedefsRemoveUnderscore(const AValue: boolean);
|
|
procedure SetUseExternal(const AValue: boolean);
|
|
procedure SetUseExternalLibname(const AValue: boolean);
|
|
procedure SetUseProcVarsForImport(const AValue: boolean);
|
|
procedure SetVarParams(const AValue: boolean);
|
|
procedure SetWin32Header(const AValue: boolean);
|
|
procedure SetUseCTypes(const AValue: boolean);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Clear(AddDefaults: boolean);
|
|
procedure Assign(Source: TPersistent); override;
|
|
function IsEqual(AProject: TH2PasProject): boolean;
|
|
procedure Load(Config: TConfigStorage);
|
|
procedure Save(Config: TConfigStorage);
|
|
procedure LoadFromFile(const AFilename: string);
|
|
procedure SaveToFile(const AFilename: string);
|
|
procedure AddFiles(List: TStrings);
|
|
procedure DeleteFiles(List: TStrings);
|
|
function CHeaderFileWithFilename(const AFilename: string): TH2PasFile;
|
|
function CHeaderFileIndexWithFilename(const AFilename: string): integer;
|
|
procedure CHeaderFileMove(OldIndex, NewIndex: integer);
|
|
function ShortenFilename(const AFilename: string): string;
|
|
function LongenFilename(const AFilename: string): string;
|
|
function NormalizeFilename(const AFilename: string): string;
|
|
function HasEnabledFiles: boolean;
|
|
procedure AddDefaultPreH2PasTools;
|
|
procedure AddDefaultPostH2PasTools;
|
|
function SearchIncludedCHeaderFile(aFile: TH2PasFile;
|
|
const SrcFilename: string): string;
|
|
function ReadAllCIncludes(ForceUpdate: boolean): TModalResult;
|
|
public
|
|
property CHeaderFileCount: integer read GetCHeaderFileCount;
|
|
property CHeaderFiles[Index: integer]: TH2PasFile read GetCHeaderFiles;
|
|
property Modified: boolean read FModified write SetModified;
|
|
property Filename: string read FFilename write SetFilename;
|
|
property BaseDir: string read FBaseDir;
|
|
property IsVirtual: boolean read FIsVirtual;
|
|
property Converter: TH2PasConverter read FConverter;
|
|
property PreH2PasTools: TComponent read FPreH2PasTools;
|
|
property PostH2PasTools: TComponent read FPostH2PasTools;
|
|
|
|
// h2pas options
|
|
property ConstantsInsteadOfEnums: boolean read FConstantsInsteadOfEnums write SetConstantsInsteadOfEnums;
|
|
property CompactOutputmode: boolean read FCompactOutputmode write SetCompactOutputmode;
|
|
property CreateIncludeFile: boolean read FCreateIncludeFile write SetCreateIncludeFile;
|
|
property Libname: string read FLibname write SetLibname;
|
|
property OutputExt: string read FOutputExt write SetOutputExt;
|
|
property PalmOSSYSTrap: boolean read FPalmOSSYSTrap write SetPalmOSSYSTrap;
|
|
property PforPointers: boolean read FPforPointers write SetPforPointers;
|
|
property PackAllRecords: boolean read FPackAllRecords write SetPackAllRecords;
|
|
property StripComments: boolean read FStripComments write SetStripComments;
|
|
property StripCommentsAndInfo: boolean read FStripCommentsAndInfo write SetStripCommentsAndInfo;
|
|
property TforTypedefs: boolean read FTforTypedefs write SetTforTypedefs;
|
|
property TforTypedefsRemoveUnderscore: boolean read FTforTypedefsRemoveUnderscore write SetTforTypedefsRemoveUnderscore;
|
|
property UseExternal: boolean read FUseExternal write SetUseExternal;
|
|
property UseExternalLibname: boolean read FUseExternalLibname write SetUseExternalLibname;
|
|
property UseProcVarsForImport: boolean read FUseProcVarsForImport write SetUseProcVarsForImport;
|
|
property VarParams: boolean read FVarParams write SetVarParams;
|
|
property Win32Header: boolean read FWin32Header write SetWin32Header;
|
|
property UseCTypes: boolean read FUseCTypes write SetUseCTypes;
|
|
property OutputDirectory: string read FOutputDirectory write SetOutputDirectory;
|
|
end;
|
|
|
|
const
|
|
SubToolH2Pas = 'h2pas';
|
|
type
|
|
{ TH2PasParser }
|
|
|
|
TH2PasParser = class(TExtToolParser)
|
|
public
|
|
class function DefaultSubTool: string; override;
|
|
procedure ReadLine(Line: string; OutputIndex: integer; IsStdErr: boolean; var {%H-}Handled: boolean
|
|
); override; // (worker thread)
|
|
end;
|
|
|
|
{ TH2PasTool }
|
|
|
|
TH2PasTool = class(TIDEExternalToolOptions)
|
|
private
|
|
FH2PasFile: TH2PasFile;
|
|
FTargetFilename: string;
|
|
public
|
|
property H2PasFile: TH2PasFile read FH2PasFile write FH2PasFile;
|
|
property TargetFilename: string read FTargetFilename write FTargetFilename;
|
|
end;
|
|
|
|
{ TH2PasConverter }
|
|
|
|
TH2PasConverter = class(TPersistent)
|
|
private
|
|
FAutoOpenLastProject: boolean;
|
|
FExecuting: boolean;
|
|
Fh2pasFilename: string;
|
|
FLastUsedFilename: string;
|
|
FModified: boolean;
|
|
FProject: TH2PasProject;
|
|
FProjectHistory: TStrings;
|
|
FWindowBounds: TRect;
|
|
function GetCurrentProjectFilename: string;
|
|
procedure SetAutoOpenLastProject(const AValue: boolean);
|
|
procedure SetCurrentProjectFilename(const AValue: string);
|
|
procedure SetProject(const AValue: TH2PasProject);
|
|
procedure SetProjectHistory(const AValue: TStrings);
|
|
procedure SetWindowBounds(const AValue: TRect);
|
|
procedure Seth2pasFilename(const AValue: string);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function IsEqual(AConverter: TH2PasConverter): boolean;
|
|
procedure Load(Config: TConfigStorage);
|
|
procedure Save(Config: TConfigStorage);
|
|
procedure LoadFromFile(const AFilename: string);
|
|
procedure SaveToFile(const AFilename: string);
|
|
procedure LoadProject(const Filename: string);
|
|
procedure SaveProject(const Filename: string);
|
|
function Execute: TModalResult;
|
|
function ConvertFile(AFile: TH2PasFile): TModalResult;
|
|
function CheckMergeDependencies: TModalResult;
|
|
function MergeIncludeFiles(AFile: TH2PasFile;
|
|
TextConverter: TIDETextConverter): TModalResult;
|
|
function GetH2PasFilename: string;
|
|
function FileIsRelated(const aFilename: string): Boolean;
|
|
public
|
|
property Project: TH2PasProject read FProject write SetProject;
|
|
property ProjectHistory: TStrings read FProjectHistory write SetProjectHistory;
|
|
property CurrentProjectFilename: string read GetCurrentProjectFilename
|
|
write SetCurrentProjectFilename;
|
|
property WindowBounds: TRect read FWindowBounds write SetWindowBounds;
|
|
property AutoOpenLastProject: boolean read FAutoOpenLastProject
|
|
write SetAutoOpenLastProject;
|
|
property h2pasFilename: string read Fh2pasFilename write Seth2pasFilename;
|
|
property Modified: boolean read FModified write FModified;
|
|
property Executing: boolean read FExecuting;
|
|
property LastUsedFilename: string read FLastUsedFilename;
|
|
end;
|
|
|
|
const
|
|
PreDefinedH2PasTypes: array[1..10] of string = (
|
|
'Char',
|
|
'Byte',
|
|
'SmallInt',
|
|
'Word',
|
|
'Longint',
|
|
'DWord',
|
|
'Int64',
|
|
'QWord',
|
|
'Single',
|
|
'Double'
|
|
);
|
|
|
|
implementation
|
|
|
|
{ TH2PasParser }
|
|
|
|
class function TH2PasParser.DefaultSubTool: string;
|
|
begin
|
|
Result:=SubToolH2Pas;
|
|
end;
|
|
|
|
procedure TH2PasParser.ReadLine(Line: string; OutputIndex: integer; IsStdErr: boolean;
|
|
var Handled: boolean);
|
|
|
|
function ReadString(var p: PChar; Expected: PChar): boolean;
|
|
begin
|
|
while Expected^<>#0 do begin
|
|
if p^<>Expected^ then exit(false);
|
|
inc(p);
|
|
inc(Expected);
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
var
|
|
p: PChar;
|
|
LineNumber: Integer;
|
|
Msg: String;
|
|
MsgLine: TMessageLine;
|
|
begin
|
|
p:=PChar(Line);
|
|
// read 'at line '
|
|
if not ReadString(p,'at line ') then exit;
|
|
// read line number
|
|
if not (p^ in ['0'..'9']) then exit;
|
|
LineNumber:=0;
|
|
while (LineNumber<999999) and (p^ in ['0'..'9']) do begin
|
|
LineNumber:=LineNumber*10+ord(p^)-ord('0');
|
|
inc(p);
|
|
end;
|
|
// read ' error : '
|
|
if not ReadString(p,' error : ') then exit;
|
|
Msg:=p;
|
|
MsgLine:=CreateMsgLine(OutputIndex);
|
|
MsgLine.SubTool:=SubToolH2Pas;
|
|
MsgLine.Urgency:=mluError;
|
|
MsgLine.Msg:=Msg;
|
|
end;
|
|
|
|
{ TH2PasFile }
|
|
|
|
procedure TH2PasFile.SetFilename(const AValue: string);
|
|
var
|
|
NewValue: String;
|
|
begin
|
|
NewValue:=TrimFilename(AValue);
|
|
if FFilename=NewValue then exit;
|
|
FFilename:=NewValue;
|
|
FCIncludesValid:=false;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasFile.SetMerge(const AValue: boolean);
|
|
begin
|
|
if FMerge=AValue then exit;
|
|
FMerge:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasFile.SetEnabled(const AValue: boolean);
|
|
begin
|
|
if FEnabled=AValue then exit;
|
|
FEnabled:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
function TH2PasFile.GetCIncludeCount: integer;
|
|
begin
|
|
if (FCIncludes=nil) or (not FCIncludesValid) then
|
|
Result:=0
|
|
else
|
|
Result:=FCIncludes.Count;
|
|
end;
|
|
|
|
function TH2PasFile.GetCIncludedBy(Index: integer): TH2PasFileCInclude;
|
|
begin
|
|
Result:=TH2PasFileCInclude(FCIncludedBy[Index]);
|
|
end;
|
|
|
|
function TH2PasFile.GetCIncludedByCount: integer;
|
|
begin
|
|
if (FCIncludedBy=nil) then
|
|
Result:=0
|
|
else
|
|
Result:=FCIncludedBy.Count;
|
|
end;
|
|
|
|
function TH2PasFile.GetCIncludes(Index: integer): TH2PasFileCInclude;
|
|
begin
|
|
Result:=TH2PasFileCInclude(FCIncludes[Index]);
|
|
end;
|
|
|
|
procedure TH2PasFile.SetModified(const AValue: boolean);
|
|
begin
|
|
if FModified=AValue then exit;
|
|
FModified:=AValue;
|
|
if FModified and (Project<>nil) then
|
|
Project.Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasFile.SetProject(const AValue: TH2PasProject);
|
|
begin
|
|
if FProject=AValue then exit;
|
|
FCIncludesValid:=false;
|
|
if FProject<>nil then begin
|
|
FProject.InternalRemoveCHeaderFile(Self);
|
|
end;
|
|
FProject:=AValue;
|
|
if FProject<>nil then begin
|
|
FProject.InternalAddCHeaderFile(Self);
|
|
end;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasFile.SearchCIncFilenames;
|
|
var
|
|
i: Integer;
|
|
IncFile: TH2PasFileCInclude;
|
|
begin
|
|
if FCIncludes=nil then exit;
|
|
if Project=nil then exit;
|
|
for i:=0 to FCIncludes.Count-1 do begin
|
|
IncFile:=CIncludes[i];
|
|
IncFile.Filename:=
|
|
Project.SearchIncludedCHeaderFile(Self,IncFile.SrcFilename);
|
|
IncFile.H2PasFile:=Project.CHeaderFileWithFilename(IncFile.Filename);
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasFile.InternalAddCIncludedBy(CIncludedBy: TH2PasFileCInclude);
|
|
begin
|
|
if FCIncludedBy=nil then
|
|
FCIncludedBy:=TFPList.Create;
|
|
FCIncludedBy.Add(CIncludedBy);
|
|
//DebugLn(['TH2PasFile.InternalAddCIncludedBy ',Filename,' included by ',CIncludedBy.Filename]);
|
|
end;
|
|
|
|
procedure TH2PasFile.InternalRemoveCIncludedBy(CIncludedBy: TH2PasFileCInclude);
|
|
begin
|
|
if FCIncludedBy=nil then exit;
|
|
FCIncludedBy.Remove(CIncludedBy);
|
|
end;
|
|
|
|
constructor TH2PasFile.Create;
|
|
begin
|
|
Clear;
|
|
end;
|
|
|
|
destructor TH2PasFile.Destroy;
|
|
begin
|
|
if FProject<>nil then begin
|
|
Project:=nil;
|
|
end;
|
|
Clear;
|
|
ClearIncludedByReferences;
|
|
FCIncludedBy.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TH2PasFile.Clear;
|
|
begin
|
|
FEnabled:=true;
|
|
FFilename:='';
|
|
FModified:=false;
|
|
FMerge:=false;
|
|
FMergedBy:=nil;
|
|
ClearCIncludes;
|
|
end;
|
|
|
|
procedure TH2PasFile.ClearIncludedByReferences;
|
|
var
|
|
i: Integer;
|
|
IncFile: TH2PasFileCInclude;
|
|
begin
|
|
if FCIncludedBy=nil then exit;
|
|
for i:=FCIncludedBy.Count-1 downto 0 do begin
|
|
IncFile:=TH2PasFileCInclude(FCIncludedBy[i]);
|
|
if IncFile=nil then continue;
|
|
IncFile.FH2PasFile:=nil;
|
|
end;
|
|
FCIncludedBy.Clear;
|
|
end;
|
|
|
|
procedure TH2PasFile.ClearCIncludes;
|
|
var
|
|
i: Integer;
|
|
IncFile: TH2PasFileCInclude;
|
|
begin
|
|
FCIncludesValid:=false;
|
|
if FCIncludes<>nil then begin
|
|
for i:=0 to FCIncludes.Count-1 do begin
|
|
IncFile:=TH2PasFileCInclude(FCIncludes[i]);
|
|
IncFile.Free;
|
|
end;
|
|
FreeAndNil(FCIncludes);
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasFile.Assign(Source: TPersistent);
|
|
var
|
|
Src: TH2PasFile;
|
|
begin
|
|
if Source is TH2PasFile then begin
|
|
Src:=TH2PasFile(Source);
|
|
if not IsEqual(Src) then begin
|
|
FEnabled:=Src.FEnabled;
|
|
FFilename:=Src.FFilename;
|
|
FCIncludesValid:=false;
|
|
Modified:=true;
|
|
end;
|
|
end else begin
|
|
inherited Assign(Source);
|
|
end;
|
|
end;
|
|
|
|
function TH2PasFile.IsEqual(AFile: TH2PasFile): boolean;
|
|
begin
|
|
Result:=(CompareFilenames(Filename,AFile.Filename)=0)
|
|
and (Enabled=AFile.Enabled)
|
|
and (Merge=AFile.Merge);
|
|
end;
|
|
|
|
procedure TH2PasFile.Load(Config: TConfigStorage);
|
|
begin
|
|
FEnabled:=Config.GetValue('Enabled/Value',true);
|
|
FMerge:=Config.GetValue('Merge/Value',true);
|
|
FFilename:=Config.GetValue('Filename/Value','');
|
|
if Project<>nil then
|
|
FFilename:=Project.NormalizeFilename(FFilename);
|
|
FCIncludesValid:=false;
|
|
FModified:=false;
|
|
end;
|
|
|
|
procedure TH2PasFile.Save(Config: TConfigStorage);
|
|
var
|
|
AFilename: String;
|
|
begin
|
|
Config.SetDeleteValue('Enabled/Value',Enabled,true);
|
|
Config.SetDeleteValue('Merge/Value',Merge,true);
|
|
AFilename:=FFilename;
|
|
if Project<>nil then
|
|
AFilename:=Project.ShortenFilename(AFilename);
|
|
Config.SetDeleteValue('Filename/Value',AFilename,'');
|
|
FModified:=false;
|
|
end;
|
|
|
|
function TH2PasFile.GetOutputFilename: string;
|
|
begin
|
|
Result:=GetOutputDirectory+ExtractFileNameOnly(Filename)+GetOutputExtension;
|
|
end;
|
|
|
|
function TH2PasFile.GetOutputDirectory: string;
|
|
begin
|
|
Result:=Project.OutputDirectory;
|
|
if Result='' then
|
|
Result:=Project.BaseDir;
|
|
end;
|
|
|
|
function TH2PasFile.GetOutputExtension: string;
|
|
begin
|
|
Result:=Project.OutputExt;
|
|
end;
|
|
|
|
function TH2PasFile.GetH2PasParameters(const InputFilename: string): string;
|
|
|
|
procedure Add(const AnOption: string);
|
|
begin
|
|
if Result<>'' then
|
|
Result:=Result+' ';
|
|
Result:=Result+AnOption;
|
|
end;
|
|
|
|
begin
|
|
Result:='';
|
|
if Project.ConstantsInsteadOfEnums then Add('-e');
|
|
if Project.CompactOutputmode then Add('-c');
|
|
if Project.CreateIncludeFile then Add('-i');
|
|
if Project.PalmOSSYSTrap then Add('-x');
|
|
if Project.PforPointers then Add('-p');
|
|
if Project.PackAllRecords then Add('-pr');
|
|
if Project.StripComments then Add('-s');
|
|
if Project.StripCommentsAndInfo then Add('-S');
|
|
if Project.TforTypedefs then Add('-t');
|
|
if Project.TforTypedefsRemoveUnderscore then Add('-T');
|
|
if Project.UseExternal then Add('-d');
|
|
if Project.UseExternalLibname then Add('-D');
|
|
if Project.UseProcVarsForImport then Add('-P');
|
|
if Project.VarParams then Add('-v');
|
|
if Project.Win32Header then Add('-w');
|
|
if Project.UseCTypes then Add('-C');
|
|
if Project.Libname<>'' then Add('-l '+Project.Libname);
|
|
Add('-o '+GetOutputFilename);
|
|
if InputFilename<>'' then
|
|
Add(InputFilename)
|
|
else
|
|
Add(Filename);
|
|
end;
|
|
|
|
function TH2PasFile.ReadCIncludes(ForceUpdate: boolean): TModalResult;
|
|
var
|
|
sl: TStringList;
|
|
i: Integer;
|
|
SrcFilename: String;
|
|
Item: TH2PasFileCInclude;
|
|
begin
|
|
if (not ForceUpdate) and CIncludesValid then exit(mrOk);
|
|
Result:=mrCancel;
|
|
if not FileExistsCached(Filename) then exit;
|
|
ClearCIncludes;
|
|
FCIncludesFileAge:=FileAgeUTF8(Filename);
|
|
FCIncludesValid:=true;
|
|
//DebugLn(['TH2PasFile.ReadCIncludes Filename="',Filename,'"']);
|
|
try
|
|
sl:=TStringList.Create;
|
|
try
|
|
sl.LoadFromFile(Filename);
|
|
for i:=0 to sl.Count-1 do begin
|
|
if not REMatches(sl[i],'^#include "(.+)"') then continue;
|
|
SrcFilename:=Trim(REVar(1));
|
|
if SrcFilename='' then continue;
|
|
// add new include
|
|
if FCIncludes=nil then FCIncludes:=TFPList.Create;
|
|
Item:=TH2PasFileCInclude.Create(Self);
|
|
Item.SrcFilename:=SrcFilename;
|
|
Item.SrcPos:=Point(1,i);
|
|
//DebugLn(['TH2PasFile.ReadCIncludes Self=',Filename,' include=',SrcFilename,' ',dbgs(Item.SrcPos)]);
|
|
FCIncludes.Add(Item);
|
|
end;
|
|
finally
|
|
sl.Free;
|
|
end;
|
|
SearchCIncFilenames;
|
|
Result:=mrOk;
|
|
except
|
|
on e: Exception do begin
|
|
DebugLn(['TH2PasFile.ReadCIncludes File="',Filename,'" Msg=',E.Message]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TH2PasFile.CIncludesValid: boolean;
|
|
begin
|
|
Result:=false;
|
|
if not FCIncludesValid then exit;
|
|
FCIncludesValid:=false;
|
|
if Project=nil then exit;
|
|
if (not FileExistsCached(Filename)) then exit;
|
|
if FileAgeUTF8(Filename)>FCIncludesFileAge then exit;
|
|
FCIncludesValid:=true;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TH2PasFile.FindCIncludedByWithOwner(ByOwner: TH2PasFile
|
|
): TH2PasFileCInclude;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FCIncludedBy<>nil then begin
|
|
for i:=0 to CIncludedByCount-1 do begin
|
|
Result:=CIncludedBy[i];
|
|
if Result.Owner=ByOwner then exit;
|
|
end;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
{ TH2PasProject }
|
|
|
|
function TH2PasProject.GetCHeaderFileCount: integer;
|
|
begin
|
|
Result:=FCHeaderFiles.Count;
|
|
end;
|
|
|
|
function TH2PasProject.GetCHeaderFiles(Index: integer): TH2PasFile;
|
|
begin
|
|
Result:=TH2PasFile(FCHeaderFiles[Index]);
|
|
end;
|
|
|
|
procedure TH2PasProject.InternalAddCHeaderFile(AFile: TH2PasFile);
|
|
begin
|
|
FCHeaderFiles.Add(AFile);
|
|
end;
|
|
|
|
procedure TH2PasProject.InternalRemoveCHeaderFile(AFile: TH2PasFile);
|
|
begin
|
|
FCHeaderFiles.Remove(AFile);
|
|
end;
|
|
|
|
procedure TH2PasProject.SetCompactOutputmode(const AValue: boolean);
|
|
begin
|
|
if FCompactOutputmode=AValue then exit;
|
|
FCompactOutputmode:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetConstantsInsteadOfEnums(const AValue: boolean);
|
|
begin
|
|
if FConstantsInsteadOfEnums=AValue then exit;
|
|
FConstantsInsteadOfEnums:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetCreateIncludeFile(const AValue: boolean);
|
|
begin
|
|
if FCreateIncludeFile=AValue then exit;
|
|
FCreateIncludeFile:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetFilename(const AValue: string);
|
|
var
|
|
NewValue: String;
|
|
begin
|
|
NewValue:=TrimFilename(AValue);
|
|
if FFilename=NewValue then exit;
|
|
FFilename:=NewValue;
|
|
FilenameChanged;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetLibname(const AValue: string);
|
|
begin
|
|
if FLibname=AValue then exit;
|
|
FLibname:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetModified(const AValue: boolean);
|
|
begin
|
|
if FModified=AValue then exit;
|
|
FModified:=AValue;
|
|
end;
|
|
|
|
procedure TH2PasProject.FilenameChanged;
|
|
begin
|
|
FIsVirtual:=(FFilename='') or (not FilenameIsAbsolute(FFilename));
|
|
FBaseDir:=ExtractFilePath(FFilename);
|
|
end;
|
|
|
|
procedure TH2PasProject.SetOutputDirectory(const AValue: string);
|
|
begin
|
|
if FOutputDirectory=AValue then exit;
|
|
FOutputDirectory:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetOutputExt(const AValue: string);
|
|
begin
|
|
if FOutputExt=AValue then exit;
|
|
FOutputExt:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetPackAllRecords(const AValue: boolean);
|
|
begin
|
|
if FPackAllRecords=AValue then exit;
|
|
FPackAllRecords:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetPalmOSSYSTrap(const AValue: boolean);
|
|
begin
|
|
if FPalmOSSYSTrap=AValue then exit;
|
|
FPalmOSSYSTrap:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetPforPointers(const AValue: boolean);
|
|
begin
|
|
if FPforPointers=AValue then exit;
|
|
FPforPointers:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetStripComments(const AValue: boolean);
|
|
begin
|
|
if FStripComments=AValue then exit;
|
|
FStripComments:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetStripCommentsAndInfo(const AValue: boolean);
|
|
begin
|
|
if FStripCommentsAndInfo=AValue then exit;
|
|
FStripCommentsAndInfo:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetTforTypedefs(const AValue: boolean);
|
|
begin
|
|
if FTforTypedefs=AValue then exit;
|
|
FTforTypedefs:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetTforTypedefsRemoveUnderscore(const AValue: boolean);
|
|
begin
|
|
if FTforTypedefsRemoveUnderscore=AValue then exit;
|
|
FTforTypedefsRemoveUnderscore:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetUseExternal(const AValue: boolean);
|
|
begin
|
|
if FUseExternal=AValue then exit;
|
|
FUseExternal:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetUseExternalLibname(const AValue: boolean);
|
|
begin
|
|
if FUseExternalLibname=AValue then exit;
|
|
FUseExternalLibname:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetUseProcVarsForImport(const AValue: boolean);
|
|
begin
|
|
if FUseProcVarsForImport=AValue then exit;
|
|
FUseProcVarsForImport:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetVarParams(const AValue: boolean);
|
|
begin
|
|
if FVarParams=AValue then exit;
|
|
FVarParams:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetWin32Header(const AValue: boolean);
|
|
begin
|
|
if FWin32Header=AValue then exit;
|
|
FWin32Header:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasProject.SetUseCTypes(const AValue: boolean);
|
|
begin
|
|
if FUseCTypes=AValue then exit;
|
|
FUseCTypes:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
constructor TH2PasProject.Create;
|
|
begin
|
|
FCHeaderFiles:=TFPList.Create;
|
|
Clear(true);
|
|
end;
|
|
|
|
destructor TH2PasProject.Destroy;
|
|
begin
|
|
Clear(false);
|
|
if (Converter<>nil) and (Converter.Project=Self) then
|
|
Converter.Project:=nil;
|
|
FreeAndNil(FCHeaderFiles);
|
|
FreeAndNil(FPreH2PasTools);
|
|
FreeAndNil(FPostH2PasTools);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TH2PasProject.Clear(AddDefaults: boolean);
|
|
begin
|
|
// FFilename is kept
|
|
FConstantsInsteadOfEnums:=true;
|
|
FCompactOutputmode:=false;
|
|
FCreateIncludeFile:=false;
|
|
FLibname:='';
|
|
FOutputExt:='.pas';
|
|
FPackAllRecords:=false;
|
|
FPalmOSSYSTrap:=false;
|
|
FPforPointers:=true;
|
|
FStripComments:=false;
|
|
FStripCommentsAndInfo:=false;
|
|
FTforTypedefs:=false;
|
|
FTforTypedefsRemoveUnderscore:=false;
|
|
FUseExternal:=false;
|
|
FUseExternalLibname:=true;
|
|
FUseProcVarsForImport:=false;
|
|
FVarParams:=false;
|
|
FWin32Header:=true;
|
|
FUseCTypes:=false;
|
|
FOutputDirectory:='';
|
|
while CHeaderFileCount>0 do
|
|
CHeaderFiles[CHeaderFileCount-1].Free;
|
|
FPreH2PasTools.Free;
|
|
FPreH2PasTools:=TComponent.Create(nil);
|
|
FPostH2PasTools.Free;
|
|
FPostH2PasTools:=TComponent.Create(nil);
|
|
if AddDefaults then
|
|
begin
|
|
AddDefaultPreH2PasTools;
|
|
AddDefaultPostH2PasTools;
|
|
end;
|
|
FModified:=false;
|
|
end;
|
|
|
|
procedure TH2PasProject.Assign(Source: TPersistent);
|
|
|
|
procedure CopyTools(SrcList: TComponent; var DestList: TComponent);
|
|
var
|
|
SrcComponent: TComponent;
|
|
NewComponent: TObject;
|
|
i: Integer;
|
|
begin
|
|
DestList.Free;
|
|
DestList:=TComponent.Create(nil);
|
|
for i:=0 to SrcList.ComponentCount-1 do begin
|
|
SrcComponent:=SrcList.Components[i];
|
|
if SrcComponent is TCustomTextConverterTool then begin
|
|
NewComponent:=
|
|
TComponentClass(SrcComponent.ClassType).Create(DestList);
|
|
TCustomTextConverterTool(NewComponent).Assign(SrcComponent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Src: TH2PasProject;
|
|
i: Integer;
|
|
NewCHeaderFile: TH2PasFile;
|
|
begin
|
|
if Source is TH2PasProject then begin
|
|
Src:=TH2PasProject(Source);
|
|
if not IsEqual(Src) then begin
|
|
// FFilename is kept
|
|
FConstantsInsteadOfEnums:=Src.FConstantsInsteadOfEnums;
|
|
FCompactOutputmode:=Src.FCompactOutputmode;
|
|
FCreateIncludeFile:=Src.FCreateIncludeFile;
|
|
FLibname:=Src.FLibname;
|
|
FOutputExt:=Src.FOutputExt;
|
|
FPackAllRecords:=Src.FPackAllRecords;
|
|
FPalmOSSYSTrap:=Src.FPalmOSSYSTrap;
|
|
FPforPointers:=Src.FPforPointers;
|
|
FStripComments:=Src.FStripComments;
|
|
FStripCommentsAndInfo:=Src.FStripCommentsAndInfo;
|
|
FTforTypedefs:=Src.FTforTypedefs;
|
|
FTforTypedefsRemoveUnderscore:=Src.FTforTypedefsRemoveUnderscore;
|
|
FUseExternal:=Src.FUseExternal;
|
|
FUseExternalLibname:=Src.FUseExternalLibname;
|
|
FUseProcVarsForImport:=Src.FUseProcVarsForImport;
|
|
FVarParams:=Src.FVarParams;
|
|
FWin32Header:=Src.FWin32Header;
|
|
FUseCTypes:=Src.FUseCTypes;
|
|
FOutputDirectory:=Src.FOutputDirectory;
|
|
Clear(false);
|
|
for i:=0 to Src.CHeaderFileCount-1 do begin
|
|
NewCHeaderFile:=TH2PasFile.Create;
|
|
NewCHeaderFile.Project:=Self;
|
|
NewCHeaderFile.Assign(Src.CHeaderFiles[i]);
|
|
end;
|
|
CopyTools(Src.FPreH2PasTools,FPreH2PasTools);
|
|
CopyTools(Src.FPostH2PasTools,FPostH2PasTools);
|
|
Modified:=true;
|
|
end;
|
|
end else begin
|
|
inherited Assign(Source);
|
|
end;
|
|
end;
|
|
|
|
function TH2PasProject.IsEqual(AProject: TH2PasProject): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result:=(AProject.CHeaderFileCount=CHeaderFileCount)
|
|
and (FConstantsInsteadOfEnums=AProject.FConstantsInsteadOfEnums)
|
|
and (FCompactOutputmode=AProject.FCompactOutputmode)
|
|
and (FCreateIncludeFile=AProject.FCreateIncludeFile)
|
|
and (FLibname=AProject.FLibname)
|
|
and (FOutputExt=AProject.FOutputExt)
|
|
and (FPackAllRecords=AProject.FPackAllRecords)
|
|
and (FPalmOSSYSTrap=AProject.FPalmOSSYSTrap)
|
|
and (FPforPointers=AProject.FPforPointers)
|
|
and (FStripComments=AProject.FStripComments)
|
|
and (FStripCommentsAndInfo=AProject.FStripCommentsAndInfo)
|
|
and (FTforTypedefs=AProject.FTforTypedefs)
|
|
and (FTforTypedefsRemoveUnderscore=AProject.FTforTypedefsRemoveUnderscore)
|
|
and (FUseExternal=AProject.FUseExternal)
|
|
and (FUseExternalLibname=AProject.FUseExternalLibname)
|
|
and (FUseProcVarsForImport=AProject.FUseProcVarsForImport)
|
|
and (FVarParams=AProject.FVarParams)
|
|
and (FWin32Header=AProject.FWin32Header)
|
|
and (FUseCTypes=AProject.FUseCTypes)
|
|
and (FOutputDirectory=AProject.FOutputDirectory);
|
|
if not Result then exit;
|
|
for i:=0 to CHeaderFileCount-1 do
|
|
if not CHeaderFiles[i].IsEqual(AProject.CHeaderFiles[i]) then
|
|
exit(false);
|
|
if (not CompareComponents(FPreH2PasTools,AProject.FPreH2PasTools))
|
|
or (not CompareComponents(FPostH2PasTools,AProject.FPostH2PasTools)) then
|
|
exit(false);
|
|
end;
|
|
|
|
procedure TH2PasProject.Load(Config: TConfigStorage);
|
|
procedure LoadTools(const SubPath: string; List: TComponent);
|
|
var
|
|
NewComponent: TComponent;
|
|
NewCount: LongInt;
|
|
i: Integer;
|
|
begin
|
|
// load PreH2PasTools
|
|
Config.AppendBasePath(SubPath);
|
|
try
|
|
NewCount:=Config.GetValue('Count',0);
|
|
for i:=0 to NewCount-1 do begin
|
|
Config.AppendBasePath('Tool'+IntToStr(i+1));
|
|
try
|
|
NewComponent:=nil;
|
|
LoadComponentFromConfig(Config,'Value',NewComponent,
|
|
@TextConverterToolClasses.FindClass,List);
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
NewCount: LongInt;
|
|
i: Integer;
|
|
NewCHeaderFile: TH2PasFile;
|
|
begin
|
|
Clear(false);
|
|
|
|
// FFilename is not saved
|
|
FConstantsInsteadOfEnums:=Config.GetValue('ConstantsInsteadOfEnums/Value',true);
|
|
FCompactOutputmode:=Config.GetValue('CompactOutputmode/Value',false);
|
|
FCreateIncludeFile:=Config.GetValue('CreateIncludeFile/Value',false);
|
|
FLibname:=Config.GetValue('Libname/Value','');
|
|
FOutputExt:=Config.GetValue('OutputExt/Value','.pas');
|
|
FPackAllRecords:=Config.GetValue('PackAllRecords/Value',false);
|
|
FPalmOSSYSTrap:=Config.GetValue('PalmOSSYSTrap/Value',false);
|
|
FPforPointers:=Config.GetValue('PforPointers/Value',true);
|
|
FStripComments:=Config.GetValue('StripComments/Value',false);
|
|
FStripCommentsAndInfo:=Config.GetValue('StripCommentsAndInfo/Value',false);
|
|
FTforTypedefs:=Config.GetValue('TforTypedefs/Value',false);
|
|
FTforTypedefsRemoveUnderscore:=Config.GetValue('TforTypedefsRemoveUnderscore/Value',false);
|
|
FUseExternal:=Config.GetValue('UseExternal/Value',false);
|
|
FUseExternalLibname:=Config.GetValue('UseExternalLibname/Value',true);
|
|
FUseProcVarsForImport:=Config.GetValue('UseProcVarsForImport/Value',false);
|
|
FVarParams:=Config.GetValue('VarParams/Value',false);
|
|
FWin32Header:=Config.GetValue('Win32Header/Value',true);
|
|
FUseCTypes:=Config.GetValue('UseCTypes/Value',false);
|
|
FOutputDirectory:=NormalizeFilename(Config.GetValue('OutputDirectory/Value',''));
|
|
|
|
// load CHeaderFiles
|
|
Config.AppendBasePath('CHeaderFiles');
|
|
try
|
|
NewCount:=Config.GetValue('Count',0);
|
|
for i:=0 to NewCount-1 do begin
|
|
Config.AppendBasePath('File'+IntToStr(i+1));
|
|
try
|
|
NewCHeaderFile:=TH2PasFile.Create;
|
|
NewCHeaderFile.Project:=Self;
|
|
NewCHeaderFile.Load(Config);
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
|
|
LoadTools('PreH2PasTools',FPreH2PasTools);
|
|
LoadTools('PostH2PasTools',FPostH2PasTools);
|
|
|
|
FModified:=false;
|
|
end;
|
|
|
|
procedure TH2PasProject.Save(Config: TConfigStorage);
|
|
|
|
procedure SaveTools(const SubPath: string; List: TComponent);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Config.AppendBasePath(SubPath);
|
|
try
|
|
Config.SetDeleteValue('Count',List.ComponentCount,0);
|
|
for i:=0 to List.ComponentCount-1 do begin
|
|
Config.AppendBasePath('Tool'+IntToStr(i+1));
|
|
try
|
|
SaveComponentToConfig(Config,'Value',List.Components[i]);
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
begin
|
|
// FFilename is kept
|
|
Config.SetDeleteValue('ConstantsInsteadOfEnums/Value',FConstantsInsteadOfEnums,true);
|
|
Config.SetDeleteValue('CompactOutputmode/Value',FCompactOutputmode,false);
|
|
Config.SetDeleteValue('CreateIncludeFile/Value',FCreateIncludeFile,false);
|
|
Config.SetDeleteValue('Libname/Value',FLibname,'');
|
|
Config.SetDeleteValue('OutputExt/Value',FOutputExt,'.pas');
|
|
Config.SetDeleteValue('PackAllRecords/Value',FPackAllRecords,false);
|
|
Config.SetDeleteValue('PalmOSSYSTrap/Value',FPalmOSSYSTrap,false);
|
|
Config.SetDeleteValue('PforPointers/Value',FPforPointers,true);
|
|
Config.SetDeleteValue('StripComments/Value',FStripComments,false);
|
|
Config.SetDeleteValue('StripCommentsAndInfo/Value',FStripCommentsAndInfo,false);
|
|
Config.SetDeleteValue('TforTypedefs/Value',FTforTypedefs,false);
|
|
Config.SetDeleteValue('TforTypedefsRemoveUnderscore/Value',FTforTypedefsRemoveUnderscore,false);
|
|
Config.SetDeleteValue('UseExternal/Value',FUseExternal,false);
|
|
Config.SetDeleteValue('UseExternalLibname/Value',FUseExternalLibname,true);
|
|
Config.SetDeleteValue('UseProcVarsForImport/Value',FUseProcVarsForImport,false);
|
|
Config.SetDeleteValue('VarParams/Value',FVarParams,false);
|
|
Config.SetDeleteValue('Win32Header/Value',FWin32Header,true);
|
|
Config.SetDeleteValue('UseCTypes/Value',FUseCTypes,false);
|
|
Config.SetDeleteValue('OutputDirectory/Value',ShortenFilename(FOutputDirectory),'');
|
|
|
|
// save CHeaderFiles
|
|
Config.AppendBasePath('CHeaderFiles');
|
|
try
|
|
Config.SetDeleteValue('Count',CHeaderFileCount,0);
|
|
for i:=0 to CHeaderFileCount-1 do begin
|
|
Config.AppendBasePath('File'+IntToStr(i+1));
|
|
try
|
|
CHeaderFiles[i].Save(Config);
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
end;
|
|
finally
|
|
Config.UndoAppendBasePath;
|
|
end;
|
|
|
|
SaveTools('PreH2PasTools',FPreH2PasTools);
|
|
SaveTools('PostH2PasTools',FPostH2PasTools);
|
|
FModified:=false;
|
|
end;
|
|
|
|
procedure TH2PasProject.LoadFromFile(const AFilename: string);
|
|
var
|
|
Config: TXMLConfigStorage;
|
|
begin
|
|
Config:=TXMLConfigStorage.Create(AFilename,true);
|
|
try
|
|
Load(Config);
|
|
finally
|
|
Config.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasProject.SaveToFile(const AFilename: string);
|
|
var
|
|
Config: TXMLConfigStorage;
|
|
begin
|
|
Config:=TXMLConfigStorage.Create(AFilename,false);
|
|
try
|
|
Save(Config);
|
|
DebugLn(['TH2PasProject.SaveToFile ',AFilename]);
|
|
Config.WriteToDisk;
|
|
finally
|
|
Config.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasProject.AddFiles(List: TStrings);
|
|
var
|
|
i: Integer;
|
|
NewFilename: string;
|
|
NewFile: TH2PasFile;
|
|
begin
|
|
if List=nil then exit;
|
|
for i:=0 to List.Count-1 do begin
|
|
NewFilename:=CleanAndExpandFilename(List[i]);
|
|
if (NewFilename='') or (not FileExistsUTF8(NewFilename)) then exit;
|
|
if CHeaderFileWithFilename(NewFilename)<>nil then exit;
|
|
NewFile:=TH2PasFile.Create;
|
|
NewFile.Project:=Self;
|
|
NewFile.Filename:=NewFilename;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasProject.DeleteFiles(List: TStrings);
|
|
var
|
|
i: Integer;
|
|
NewFilename: String;
|
|
CurFile: TH2PasFile;
|
|
begin
|
|
if List=nil then exit;
|
|
for i:=0 to List.Count-1 do begin
|
|
NewFilename:=CleanAndExpandFilename(List[i]);
|
|
if (NewFilename='') then exit;
|
|
CurFile:=CHeaderFileWithFilename(NewFilename);
|
|
if CurFile<>nil then begin
|
|
CurFile.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TH2PasProject.CHeaderFileWithFilename(const AFilename: string
|
|
): TH2PasFile;
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i:=CHeaderFileIndexWithFilename(AFilename);
|
|
if i>=0 then
|
|
Result:=CHeaderFiles[i]
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TH2PasProject.CHeaderFileIndexWithFilename(const AFilename: string
|
|
): integer;
|
|
begin
|
|
Result:=CHeaderFileCount-1;
|
|
while (Result>=0)
|
|
and (CompareFilenames(AFilename,CHeaderFiles[Result].Filename)<>0) do
|
|
dec(Result);
|
|
end;
|
|
|
|
procedure TH2PasProject.CHeaderFileMove(OldIndex, NewIndex: integer);
|
|
begin
|
|
FCHeaderFiles.Move(OldIndex,NewIndex);
|
|
end;
|
|
|
|
function TH2PasProject.ShortenFilename(const AFilename: string): string;
|
|
begin
|
|
if IsVirtual then
|
|
Result:=AFilename
|
|
else
|
|
Result:=CreateRelativePath(AFilename,fBaseDir);
|
|
end;
|
|
|
|
function TH2PasProject.LongenFilename(const AFilename: string): string;
|
|
begin
|
|
if IsVirtual then
|
|
Result:=AFilename
|
|
else if not FilenameIsAbsolute(AFilename) then
|
|
Result:=TrimFilename(BaseDir+AFilename);
|
|
end;
|
|
|
|
function TH2PasProject.NormalizeFilename(const AFilename: string): string;
|
|
begin
|
|
Result:=LongenFilename(GetForcedPathDelims(AFilename));
|
|
end;
|
|
|
|
function TH2PasProject.HasEnabledFiles: boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to CHeaderFileCount-1 do
|
|
if CHeaderFiles[i].Enabled and (not CHeaderFiles[i].Merge) then exit(true);
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TH2PasProject.AddDefaultPreH2PasTools;
|
|
begin
|
|
AddNewTextConverterTool(FPreH2PasTools,TPreH2PasTools);
|
|
end;
|
|
|
|
procedure TH2PasProject.AddDefaultPostH2PasTools;
|
|
begin
|
|
AddNewTextConverterTool(FPostH2PasTools,TPostH2PasTools);
|
|
end;
|
|
|
|
function TH2PasProject.SearchIncludedCHeaderFile(aFile: TH2PasFile;
|
|
const SrcFilename: string): string;
|
|
var
|
|
AFilename: String;
|
|
i: Integer;
|
|
CurFile: TH2PasFile;
|
|
begin
|
|
AFilename:=GetForcedPathDelims(SrcFilename);
|
|
if System.Pos(PathDelim,AFilename)>0 then begin
|
|
// with sub path -> only search relative to AFile
|
|
Result:=TrimFilename(ExtractFilePath(aFile.Filename)+AFilename);
|
|
if FileExistsCached(Result) then exit;
|
|
end else begin
|
|
// search relative to AFile
|
|
Result:=TrimFilename(ExtractFilePath(aFile.Filename)+AFilename);
|
|
if FileExistsCached(Result) then exit;
|
|
// search relative to all other .h files
|
|
for i:=0 to CHeaderFileCount-1 do begin
|
|
CurFile:=CHeaderFiles[i];
|
|
Result:=TrimFilename(ExtractFilePath(CurFile.Filename)+AFilename);
|
|
if FileExistsCached(Result) then exit;
|
|
end;
|
|
end;
|
|
Result:='';
|
|
end;
|
|
|
|
function TH2PasProject.ReadAllCIncludes(ForceUpdate: boolean): TModalResult;
|
|
var
|
|
i: Integer;
|
|
CurFile: TH2PasFile;
|
|
DefaultMergeFile: TH2PasFile;
|
|
begin
|
|
// read includes
|
|
DefaultMergeFile:=nil;
|
|
for i:=0 to CHeaderFileCount-1 do begin
|
|
CurFile:=CHeaderFiles[i];
|
|
CurFile.FMergedBy:=nil;
|
|
Result:=CurFile.ReadCIncludes(ForceUpdate);
|
|
if Result=mrAbort then exit;
|
|
if (not CurFile.Merge) then
|
|
DefaultMergeFile:=CurFile;
|
|
end;
|
|
|
|
// create merge connections
|
|
for i:=0 to CHeaderFileCount-1 do begin
|
|
CurFile:=CHeaderFiles[i];
|
|
if CurFile.Merge and (CurFile.CIncludedByCount=0) then begin
|
|
// this file should be merged, but is not included by any other file
|
|
// append it to the first unit
|
|
CurFile.FMergedBy:=DefaultMergeFile;
|
|
end;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TH2PasConverter }
|
|
|
|
function TH2PasConverter.GetCurrentProjectFilename: string;
|
|
begin
|
|
if FProjectHistory.Count>0 then
|
|
Result:=FProjectHistory[FProjectHistory.Count-1]
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
procedure TH2PasConverter.SetAutoOpenLastProject(const AValue: boolean);
|
|
begin
|
|
if FAutoOpenLastProject=AValue then exit;
|
|
FAutoOpenLastProject:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasConverter.SetCurrentProjectFilename(const AValue: string);
|
|
const
|
|
ProjectHistoryMax=30;
|
|
var
|
|
NewValue: String;
|
|
begin
|
|
NewValue:=TrimFilename(AValue);
|
|
if NewValue='' then exit;
|
|
if CompareFilenames(GetCurrentProjectFilename,NewValue)=0 then exit;
|
|
FProjectHistory.Add(NewValue);
|
|
while FProjectHistory.Count>ProjectHistoryMax do
|
|
FProjectHistory.Delete(0);
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasConverter.SetProject(const AValue: TH2PasProject);
|
|
begin
|
|
if FProject=AValue then exit;
|
|
if FProject<>nil then begin
|
|
FProject.fConverter:=nil;
|
|
end;
|
|
FProject:=AValue;
|
|
if FProject<>nil then begin
|
|
FProject.fConverter:=Self;
|
|
if FProject.Filename<>'' then
|
|
CurrentProjectFilename:=FProject.Filename;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasConverter.SetProjectHistory(const AValue: TStrings);
|
|
begin
|
|
if FProjectHistory=AValue then exit;
|
|
FProjectHistory.Assign(AValue);
|
|
end;
|
|
|
|
procedure TH2PasConverter.SetWindowBounds(const AValue: TRect);
|
|
begin
|
|
if SameRect(@FWindowBounds,@AValue) then exit;
|
|
FWindowBounds:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
procedure TH2PasConverter.Seth2pasFilename(const AValue: string);
|
|
begin
|
|
if Fh2pasFilename=AValue then exit;
|
|
Fh2pasFilename:=AValue;
|
|
Modified:=true;
|
|
end;
|
|
|
|
constructor TH2PasConverter.Create;
|
|
begin
|
|
FProjectHistory:=TStringList.Create;
|
|
Clear;
|
|
end;
|
|
|
|
destructor TH2PasConverter.Destroy;
|
|
begin
|
|
FreeAndNil(FProject);
|
|
Clear;
|
|
FreeAndNil(FProjectHistory);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TH2PasConverter.Clear;
|
|
begin
|
|
FAutoOpenLastProject:=true;
|
|
if FProject<>nil then FreeAndNil(FProject);
|
|
FProjectHistory.Clear;
|
|
FWindowBounds:=Rect(0,0,0,0);
|
|
Fh2pasFilename:='h2pas';
|
|
FModified:=false;
|
|
end;
|
|
|
|
procedure TH2PasConverter.Assign(Source: TPersistent);
|
|
var
|
|
Src: TH2PasConverter;
|
|
begin
|
|
if Source is TH2PasConverter then begin
|
|
Src:=TH2PasConverter(Source);
|
|
if not IsEqual(Src) then begin
|
|
Clear;
|
|
// Note: project is kept unchanged
|
|
FProjectHistory.Assign(Src.FProjectHistory);
|
|
FWindowBounds:=Src.FWindowBounds;
|
|
Fh2pasFilename:=Src.Fh2pasFilename;
|
|
Modified:=true;
|
|
end;
|
|
end else begin
|
|
inherited Assign(Source);
|
|
end;
|
|
end;
|
|
|
|
function TH2PasConverter.IsEqual(AConverter: TH2PasConverter): boolean;
|
|
begin
|
|
if (FAutoOpenLastProject<>AConverter.FAutoOpenLastProject)
|
|
or (not SameRect(@FWindowBounds,@AConverter.FWindowBounds))
|
|
or (Fh2pasFilename<>AConverter.h2pasFilename)
|
|
or (not FProjectHistory.Equals(AConverter.FProjectHistory))
|
|
then
|
|
exit(false);
|
|
Result:=true;
|
|
end;
|
|
|
|
procedure TH2PasConverter.Load(Config: TConfigStorage);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FAutoOpenLastProject:=Config.GetValue('AutoOpenLastProject/Value',true);
|
|
Fh2pasFilename:=Config.GetValue('h2pas/Filename','h2pas');
|
|
Config.GetValue('WindowBounds/',FWindowBounds,Rect(0,0,0,0));
|
|
Config.GetValue('ProjectHistory/',FProjectHistory);
|
|
for i:=FProjectHistory.Count-1 downto 0 do
|
|
if FProjectHistory[i]='' then FProjectHistory.Delete(i);
|
|
|
|
// Note: project is saved in its own file
|
|
end;
|
|
|
|
procedure TH2PasConverter.Save(Config: TConfigStorage);
|
|
begin
|
|
Config.SetDeleteValue('AutoOpenLastProject/Value',FAutoOpenLastProject,true);
|
|
Config.SetDeleteValue('h2pas/Filename',Fh2pasFilename,'h2pas');
|
|
Config.SetDeleteValue('WindowBounds/',FWindowBounds,Rect(0,0,0,0));
|
|
Config.SetValue('ProjectHistory/',FProjectHistory);
|
|
end;
|
|
|
|
procedure TH2PasConverter.LoadFromFile(const AFilename: string);
|
|
var
|
|
Config: TXMLConfigStorage;
|
|
begin
|
|
Config:=TXMLConfigStorage.Create(AFilename,true);
|
|
try
|
|
Load(Config);
|
|
finally
|
|
Config.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasConverter.SaveToFile(const AFilename: string);
|
|
var
|
|
Config: TXMLConfigStorage;
|
|
begin
|
|
Config:=TXMLConfigStorage.Create(AFilename,false);
|
|
try
|
|
Save(Config);
|
|
Config.WriteToDisk;
|
|
finally
|
|
Config.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TH2PasConverter.LoadProject(const Filename: string);
|
|
begin
|
|
DebugLn(['TH2PasConverter.LoadProject ',Filename]);
|
|
if FProject=nil then
|
|
FProject:=TH2PasProject.Create;
|
|
FProject.Filename:=Filename;
|
|
FProject.LoadFromFile(Filename);
|
|
CurrentProjectFilename:=Filename;
|
|
end;
|
|
|
|
procedure TH2PasConverter.SaveProject(const Filename: string);
|
|
begin
|
|
DebugLn(['TH2PasConverter.SaveProject ',Filename]);
|
|
FProject.Filename:=Filename;
|
|
FProject.SaveToFile(Filename);
|
|
CurrentProjectFilename:=Filename;
|
|
end;
|
|
|
|
function TH2PasConverter.Execute: TModalResult;
|
|
var
|
|
i: Integer;
|
|
AFile: TH2PasFile;
|
|
CurResult: TModalResult;
|
|
begin
|
|
if FExecuting then begin
|
|
DebugLn(['TH2PasConverter.Execute FAILED: Already executing']);
|
|
exit(mrCancel);
|
|
end;
|
|
|
|
Result:=mrOK;
|
|
FExecuting:=true;
|
|
try
|
|
FLastUsedFilename:='';
|
|
|
|
CurResult:=CheckMergeDependencies;
|
|
if CurResult=mrAbort then begin
|
|
DebugLn(['TH2PasConverter.Execute aborted because merging not possible']);
|
|
exit(mrAbort);
|
|
end;
|
|
|
|
// convert every c header file
|
|
for i:=0 to Project.CHeaderFileCount-1 do begin
|
|
AFile:=Project.CHeaderFiles[i];
|
|
if not AFile.Enabled then continue;
|
|
if AFile.Merge then continue;
|
|
CurResult:=ConvertFile(AFile);
|
|
if CurResult=mrAbort then begin
|
|
DebugLn(['TH2PasConverter.Execute aborted on file ',AFile.Filename]);
|
|
exit(mrAbort);
|
|
end;
|
|
if CurResult<>mrOK then Result:=mrCancel;
|
|
end;
|
|
finally
|
|
FExecuting:=false;
|
|
end;
|
|
end;
|
|
|
|
function TH2PasConverter.ConvertFile(AFile: TH2PasFile): TModalResult;
|
|
var
|
|
TextConverter: TIDETextConverter;
|
|
|
|
procedure CloseOrRevertEditorFile(const Filename: string);
|
|
begin
|
|
if FileExistsUTF8(Filename) then
|
|
LazarusIDE.DoRevertEditorFile(Filename)
|
|
else
|
|
LazarusIDE.DoCloseEditorFile(Filename,[cfQuiet]);
|
|
end;
|
|
|
|
function ExecuteTools(List: TComponent; const DefaultFilename: string
|
|
): TModalResult;
|
|
var
|
|
ErrorComponent: TComponent;
|
|
ErrorTool: TCustomTextConverterTool;
|
|
ErrMsg: String;
|
|
Line: Integer;
|
|
Col: Integer;
|
|
Filename: String;
|
|
BaseDir: String;
|
|
begin
|
|
Result:=TextConverter.Execute(List,ErrorComponent);
|
|
if Result=mrOk then exit;
|
|
Line:=0;
|
|
Col:=0;
|
|
Filename:='';
|
|
if ErrorComponent is TCustomTextConverterTool then begin
|
|
ErrorTool:=TCustomTextConverterTool(ErrorComponent);
|
|
Line:=ErrorTool.ErrorLine;
|
|
Col:=ErrorTool.ErrorColumn;
|
|
Filename:=ErrorTool.ErrorFilename;
|
|
end;
|
|
if Filename='' then
|
|
Filename:=DefaultFilename;
|
|
// create error message
|
|
BaseDir:=ExtractFilePath(Project.BaseDir);
|
|
ErrMsg:=CreateRelativePath(Filename,BaseDir);
|
|
|
|
if Line>0 then begin
|
|
ErrMsg:=ErrMsg+'('+IntToStr(Line)+',';
|
|
if Col>0 then
|
|
ErrMsg:=ErrMsg+IntToStr(Col)
|
|
else
|
|
ErrMsg:=ErrMsg+'1';
|
|
ErrMsg:=ErrMsg+')';
|
|
end;
|
|
ErrMsg:=ErrMsg+' Error: '+ErrorTool.ErrorMsg+' ('+ErrorTool.Caption+')';
|
|
DebugLn(['TH2PasConverter.ConvertFile Failed: ',ErrMsg]);
|
|
IDEMessagesWindow.AddCustomMessage(mluError,ErrorTool.ErrorMsg,Filename,Line,Col,ErrorTool.Caption);
|
|
LazarusIDE.DoJumpToCompilerMessage(true);
|
|
Result:=mrAbort;
|
|
end;
|
|
|
|
var
|
|
OutputFilename: String;
|
|
TempCHeaderFilename: String;
|
|
InputFilename: String;
|
|
Tool: TH2PasTool;
|
|
begin
|
|
Result:=mrCancel;
|
|
FLastUsedFilename:='';
|
|
|
|
// check if file exists
|
|
InputFilename:=AFile.Filename;
|
|
if not FileExistsCached(InputFilename) then begin
|
|
Result := IDEMessageDialog(h2pFileNotFound,
|
|
Format(h2pCHeaderFileNotFound, [InputFilename]),
|
|
mtError,[mbCancel,mbAbort],'');
|
|
exit;
|
|
end;
|
|
|
|
OutputFilename:=AFile.GetOutputFilename;
|
|
TempCHeaderFilename:=ChangeFileExt(OutputFilename,'.tmp.h');
|
|
TextConverter:=TIDETextConverter.Create(nil);
|
|
try
|
|
if not CopyFile(InputFilename,TempCHeaderFilename) then begin
|
|
Result := IDEMessageDialog(h2pCopyingFileFailed,
|
|
Format(h2pUnableToCopyFileTo, [InputFilename, #13, TempCHeaderFilename]),
|
|
mtError,[mbCancel,mbAbort],'');
|
|
exit;
|
|
end;
|
|
|
|
TextConverter.Filename:=TempCHeaderFilename;
|
|
FLastUsedFilename:=TextConverter.Filename;
|
|
DebugLn(['TH2PasConverter.ConvertFile TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' FileSize=',FileSize(TempCHeaderFilename)]);
|
|
|
|
// merge files
|
|
TextConverter.LoadFromFile(InputFilename);
|
|
Result:=MergeIncludeFiles(AFile,TextConverter);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TH2PasConverter.ConvertFile Failed merging include files in ',TempCHeaderFilename]);
|
|
exit;
|
|
end;
|
|
|
|
// run converters for .h file to make it compatible for h2pas
|
|
Result:=ExecuteTools(Project.PreH2PasTools,TempCHeaderFilename);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TH2PasConverter.ConvertFile Failed running Project.PreH2PasTools on ',TempCHeaderFilename]);
|
|
exit;
|
|
end;
|
|
|
|
//DebugLn(['TH2PasConverter.ConvertFile CCC1 ',TextConverter.Source]);
|
|
// run h2pas
|
|
Tool:=TH2PasTool.Create;
|
|
try
|
|
Tool.Title:='h2pas';
|
|
Tool.H2PasFile:=AFile;
|
|
Tool.TargetFilename:=TextConverter.Filename;
|
|
Tool.Executable:=GetH2PasFilename;
|
|
Tool.CmdLineParams:=AFile.GetH2PasParameters(Tool.TargetFilename);
|
|
Tool.WorkingDirectory:=Project.BaseDir;
|
|
DebugLn(['TH2PasConverter.ConvertFile Tool.Executable="',Tool.Executable,'" Tool.CmdLineParams="',Tool.CmdLineParams,'"']);
|
|
Tool.Parsers.Add(SubToolH2Pas);
|
|
if not RunExternalTool(Tool) then
|
|
exit(mrAbort);
|
|
if IDEMessagesWindow.SelectFirstUrgentMessage(mluError,false) then
|
|
exit(mrAbort);
|
|
finally
|
|
Tool.Free;
|
|
end;
|
|
|
|
// run beautification tools for new pascal code
|
|
TextConverter.InitWithFilename(OutputFilename);
|
|
//DebugLn(['TH2PasConverter.ConvertFile Output: ',copy(TextConverter.Source,1,300)]);
|
|
//DebugLn(['TH2PasConverter.ConvertFile CCC2 ',TextConverter.Source]);
|
|
Result:=ExecuteTools(Project.PostH2PasTools,OutputFilename);
|
|
if Result<>mrOk then begin
|
|
DebugLn(['TH2PasConverter.ConvertFile Failed running Project.PostH2PasTools on ',OutputFilename]);
|
|
exit;
|
|
end;
|
|
TextConverter.Filename:=OutputFilename;// save
|
|
|
|
// clean up
|
|
if FileExistsUTF8(TempCHeaderFilename) then
|
|
DeleteFileUTF8(TempCHeaderFilename);
|
|
finally
|
|
TextConverter.Free;
|
|
if (LazarusIDE<>nil) then begin
|
|
// reload changed files, so that IDE does not report changed files
|
|
CloseOrRevertEditorFile(TempCHeaderFilename);
|
|
CloseOrRevertEditorFile(OutputFilename);
|
|
end;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TH2PasConverter.CheckMergeDependencies: TModalResult;
|
|
var
|
|
CheckedFiles: TFPList;
|
|
|
|
procedure AddIncludedByFiles(IncludedByFiles: TFPList; CurFile: TH2PasFile);
|
|
var
|
|
i: Integer;
|
|
IncludedBy: TH2PasFile;
|
|
begin
|
|
if CheckedFiles.IndexOf(CurFile)>=0 then exit;
|
|
CheckedFiles.Add(CurFile);
|
|
for i:=0 to CurFile.CIncludedByCount-1 do begin
|
|
IncludedBy:=CurFile.CIncludedBy[i].Owner;
|
|
if IncludedBy.Merge then
|
|
AddIncludedByFiles(IncludedByFiles,IncludedBy)
|
|
else
|
|
if IncludedByFiles.IndexOf(IncludedBy)<0 then
|
|
IncludedByFiles.Add(IncludedBy);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
CurFile: TH2PasFile;
|
|
j: Integer;
|
|
IncludedByFiles: TFPList;
|
|
Warning: String;
|
|
begin
|
|
// update graph
|
|
Result:=Project.ReadAllCIncludes(true);
|
|
if Result=mrAbort then begin
|
|
DebugLn(['TH2PasConverter.CheckMergeDependencies aborted reading all include dependencies']);
|
|
exit;
|
|
end;
|
|
|
|
Warning:='';
|
|
for i:=0 to Project.CHeaderFileCount-1 do begin
|
|
CurFile:=Project.CHeaderFiles[i];
|
|
if CurFile.Merge then begin
|
|
// this file should be merged
|
|
// -> check if it is included only once
|
|
IncludedByFiles:=TFPList.Create;
|
|
CheckedFiles:=TFPList.Create;
|
|
AddIncludedByFiles(IncludedByFiles,CurFile);
|
|
if IncludedByFiles.Count>1 then begin
|
|
// this merged file is included by more than one unit
|
|
Warning := Format(h2pWarningTheFileWillBeMergedIntoMultipleFiles, [Warning, Project.ShortenFilename(CurFile.Filename), #13, #13]);
|
|
for j:=0 to IncludedByFiles.Count-1 do begin
|
|
if j>0 then
|
|
Warning:=Warning+', ';
|
|
Warning:=Warning
|
|
+Project.ShortenFilename(TH2PasFile(IncludedByFiles[j]).Filename);
|
|
end;
|
|
Warning:=Warning+#13;
|
|
end;
|
|
CheckedFiles.Free;
|
|
IncludedByFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
if Warning<>'' then begin
|
|
Result := MessageDlg(h2pWarning,
|
|
Format(h2pAmbiguousMerges, [#13, Warning]), mtWarning, [mbIgnore, mbAbort], 0);
|
|
if Result<>mrIgnore then exit(mrCancel);
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TH2PasConverter.MergeIncludeFiles(AFile: TH2PasFile;
|
|
TextConverter: TIDETextConverter): TModalResult;
|
|
|
|
procedure GetIncludeMergeFiles(MergedFiles: TFPList; CurFile: TH2PasFile);
|
|
var
|
|
i: Integer;
|
|
CInclude: TH2PasFileCInclude;
|
|
IncFile: TH2PasFile;
|
|
begin
|
|
//DebugLn(['GetMergeFiles CurFile=',CurFile.Filename,' CurFile.CIncludeCount=',CurFile.CIncludeCount]);
|
|
// merge include files
|
|
for i:=0 to CurFile.CIncludeCount-1 do begin
|
|
CInclude:=CurFile.CIncludes[i];
|
|
IncFile:=CInclude.H2PasFile;
|
|
if IncFile=nil then continue;
|
|
//DebugLn(['GetMergeFiles AFile=',AFile.Filename,' CInclude=',CInclude.Filename,' IncFile.Merge=',IncFile.Merge,' ']);
|
|
if not IncFile.Merge then continue;
|
|
if not IncFile.Enabled then continue;
|
|
if IncFile=AFile then continue;
|
|
if MergedFiles.IndexOf(IncFile)<0 then begin
|
|
MergedFiles.Add(IncFile);
|
|
GetIncludeMergeFiles(MergedFiles,IncFile);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure GetProjectMergeFiles(MergedFiles: TFPList; CurFile: TH2PasFile);
|
|
var
|
|
IncFile: TH2PasFile;
|
|
i: Integer;
|
|
begin
|
|
// merge non include files
|
|
if Project<>nil then begin
|
|
for i:=0 to Project.CHeaderFileCount-1 do begin
|
|
IncFile:=Project.CHeaderFiles[i];
|
|
if not IncFile.Enabled then continue;
|
|
if IncFile=CurFile then continue;
|
|
if IncFile.MergedBy=CurFile then begin
|
|
if MergedFiles.IndexOf(IncFile)<0 then begin
|
|
MergedFiles.Add(IncFile);
|
|
GetIncludeMergeFiles(MergedFiles,IncFile);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
MergedFiles: TFPList;// list of TH2PasFile
|
|
i: Integer;
|
|
IncludeFile: TH2PasFile;
|
|
fs: TFileStream;
|
|
s: string;
|
|
begin
|
|
Result:=mrCancel;
|
|
MergedFiles:=TFPList.Create;
|
|
try
|
|
GetIncludeMergeFiles(MergedFiles,AFile);
|
|
GetProjectMergeFiles(MergedFiles,AFile);
|
|
for i:=0 to MergedFiles.Count-1 do begin
|
|
IncludeFile:=TH2PasFile(MergedFiles[i]);
|
|
DebugLn(['TH2PasConverter.MergeIncludeFiles merging file '
|
|
,'"'+IncludeFile.Filename+'"'+' into "'+TextConverter.Filename+'"']);
|
|
try
|
|
fs:=TFileStream.Create(IncludeFile.Filename,fmOpenRead);
|
|
try
|
|
SetLength(s,fs.Size);
|
|
if s<>'' then begin
|
|
fs.Read(s[1],length(s));
|
|
TextConverter.Source:=TextConverter.Source+LineEnding+s;
|
|
end;
|
|
finally
|
|
fs.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(h2pError, Format(h2pUnableToMergeFileInto, [IncludeFile.Filename, TextConverter.Filename]), mtError, [mbCancel], 0);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
finally
|
|
MergedFiles.Free;
|
|
end;
|
|
end;
|
|
|
|
function TH2PasConverter.GetH2PasFilename: string;
|
|
begin
|
|
Result:=FindDefaultExecutablePath(h2pasFilename);
|
|
end;
|
|
|
|
function TH2PasConverter.FileIsRelated(const aFilename: string): Boolean;
|
|
begin
|
|
Result:=(CompareFilenames(AFilename,LastUsedFilename)=0)
|
|
or ((Project<>nil) and (Project.CHeaderFileWithFilename(aFilename)<>nil));
|
|
end;
|
|
|
|
{ TRemoveCPlusPlusExternCTool }
|
|
|
|
class function TRemoveCPlusPlusExternCTool.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveCExternCLines;
|
|
end;
|
|
|
|
function TRemoveCPlusPlusExternCTool.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
i: Integer;
|
|
Lines: TStrings;
|
|
Line: string;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Trim(Lines[i]);
|
|
if Line='extern "C" {' then begin
|
|
Lines[i]:='';
|
|
end
|
|
else if (i>0) and (Line='}')
|
|
and ((Lines[i-1]='#if defined(__cplusplus)')
|
|
or (Lines[i-1]='#ifdef __cplusplus'))
|
|
then begin
|
|
Lines[i]:='';
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TRemoveEmptyCMacrosTool }
|
|
|
|
class function TRemoveEmptyCMacrosTool.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveEmptyCMacros;
|
|
end;
|
|
|
|
function TRemoveEmptyCMacrosTool.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
EmptyMacros: TAVLTree;// tree of PChar
|
|
|
|
procedure AddEmptyMacro(const MacroName: string);
|
|
var
|
|
TempStr: String;
|
|
Identifier: PChar;
|
|
begin
|
|
//DebugLn(['AddEmptyMacro MacroName="',MacroName,'"']);
|
|
if EmptyMacros=nil then
|
|
EmptyMacros:=TAVLTree.Create(TListSortCompare(@CompareIdentifiers));
|
|
Identifier:=@MacroName[1];
|
|
if EmptyMacros.Find(Identifier)<>nil then exit;
|
|
TempStr:=MacroName; // increase refcount
|
|
if TempStr<>'' then
|
|
Pointer(TempStr):=nil;
|
|
EmptyMacros.Add(Identifier);
|
|
end;
|
|
|
|
procedure DeleteEmptyMacro(const MacroName: string);
|
|
var
|
|
OldMacroName: String;
|
|
Identifier: PChar;
|
|
Node: TAVLTreeNode;
|
|
begin
|
|
//DebugLn(['DeleteEmptyMacro MacroName="',MacroName,'"']);
|
|
if EmptyMacros=nil then exit;
|
|
Identifier:=@MacroName[1];
|
|
Node:=EmptyMacros.Find(Identifier);
|
|
if Node=nil then exit;
|
|
OldMacroName:='';
|
|
Pointer(OldMacroName):=Node.Data;
|
|
if OldMacroName<>'' then OldMacroName:=''; // decrease refcount
|
|
EmptyMacros.Delete(Node);
|
|
end;
|
|
|
|
procedure FreeMacros;
|
|
var
|
|
CurMacroName: String;
|
|
Node: TAVLTreeNode;
|
|
begin
|
|
if EmptyMacros=nil then exit;
|
|
CurMacroName:='';
|
|
Node:=EmptyMacros.FindLowest;
|
|
while Node<>nil do begin
|
|
Pointer(CurMacroName):=Node.Data;
|
|
if CurMacroName<>'' then CurMacroName:=''; // decrease refcount
|
|
Node:=EmptyMacros.FindSuccessor(Node);
|
|
end;
|
|
EmptyMacros.Free;
|
|
end;
|
|
|
|
procedure RemoveEmptyMacrosFromString(var s: string);
|
|
var
|
|
IdentEnd: Integer;
|
|
IdentStart: LongInt;
|
|
Identifier: PChar;
|
|
IdentLen: LongInt;
|
|
begin
|
|
if EmptyMacros=nil then exit;
|
|
IdentEnd:=1;
|
|
repeat
|
|
IdentStart:=FindNextIdentifier(s,IdentEnd,length(s));
|
|
if IdentStart>length(s) then exit;
|
|
Identifier:=@s[IdentStart];
|
|
IdentLen:=GetIdentLen(Identifier);
|
|
if EmptyMacros.Find(Identifier)<>nil then begin
|
|
// empty macro found -> remove
|
|
System.Delete(s,IdentStart,IdentLen);
|
|
IdentEnd:=IdentStart;
|
|
end else begin
|
|
IdentEnd:=IdentStart+IdentLen;
|
|
end;
|
|
until false;
|
|
end;
|
|
|
|
var
|
|
MacroStart, MacroLen: integer;
|
|
Lines: TStrings;
|
|
i: Integer;
|
|
Line: string;
|
|
MacroName: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
EmptyMacros:=nil;
|
|
try
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Lines[i];
|
|
if REMatches(Line,'^#define\s+([a-zA-Z0-9_]+)\b(.*)$') then begin
|
|
REVarPos(1,MacroStart,MacroLen);
|
|
MacroName:=copy(Line,MacroStart,MacroLen);
|
|
if Trim(copy(Line,MacroStart+MacroLen,length(Line)))='' then
|
|
AddEmptyMacro(MacroName)
|
|
else
|
|
DeleteEmptyMacro(MacroName);
|
|
end;
|
|
if (Line<>'') and (Line[1]<>'#') then
|
|
RemoveEmptyMacrosFromString(Line);
|
|
Lines[i]:=Line;
|
|
inc(i);
|
|
end;
|
|
finally
|
|
FreeMacros;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TReplaceMacro0PointerWithNULL }
|
|
|
|
class function TReplaceMacro0PointerWithNULL.ClassDescription: string;
|
|
begin
|
|
Result := h2pReplaceMacroValues0PointerLikeChar0WithNULL;
|
|
end;
|
|
|
|
function TReplaceMacro0PointerWithNULL.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Lines: TStrings;
|
|
i: Integer;
|
|
Line: string;
|
|
MacroStart, MacroLen: integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Lines[i];
|
|
// example: #define MPI_ARGV_NULL (char **)0
|
|
if REMatches(Line,'^#define\s+([a-zA-Z0-9_]+)\s+(\(.*\*\)0)\s*($|//|/\*)')
|
|
then begin
|
|
REVarPos(2,MacroStart,MacroLen);
|
|
Line:=copy(Line,1,MacroStart-1)+'NULL'
|
|
+copy(Line,MacroStart+MacroLen,length(Line));
|
|
Lines[i]:=Line;
|
|
end
|
|
else // example: #define MPI_NULL_COPY_FN ((MPI_Copy_function *)0)
|
|
if REMatches(Line,'^#define\s+([a-zA-Z0-9_]+)\s+(\(\(.*\*\)0\))\s*($|//|/\*)')
|
|
then begin
|
|
REVarPos(2,MacroStart,MacroLen);
|
|
Line:=copy(Line,1,MacroStart-1)+'NULL'
|
|
+copy(Line,MacroStart+MacroLen,length(Line));
|
|
Lines[i]:=Line;
|
|
end
|
|
else // example: *)0)
|
|
if REMatches(Line,'\*\)(0)\)')
|
|
then begin
|
|
REVarPos(1,MacroStart,MacroLen);
|
|
Line:=copy(Line,1,MacroStart-1)+'NULL'
|
|
+copy(Line,MacroStart+MacroLen,length(Line));
|
|
Lines[i]:=Line;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TReplaceEdgedBracketPairWithStar }
|
|
|
|
class function TReplaceEdgedBracketPairWithStar.ClassDescription: string;
|
|
begin
|
|
Result := h2pReplaceWith;
|
|
end;
|
|
|
|
constructor TReplaceEdgedBracketPairWithStar.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
SearchFor:='[]';
|
|
ReplaceWith:='*';
|
|
end;
|
|
|
|
{ TReplaceUnitFilenameWithUnitName }
|
|
|
|
class function TReplaceUnitFilenameWithUnitName.ClassDescription: string;
|
|
begin
|
|
Result := h2pReplaceUnitFilenameWithUnitName;
|
|
end;
|
|
|
|
constructor TReplaceUnitFilenameWithUnitName.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
SearchFor:='^(unit\s).*(/|\\)([a-z_0-9]+;)';
|
|
ReplaceWith:='$1$3';
|
|
Options:=Options+[trtRegExpr];
|
|
end;
|
|
|
|
{ TRemoveSystemTypes }
|
|
|
|
class function TRemoveSystemTypes.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveTypeRedefinitionsLikePLongint;
|
|
end;
|
|
|
|
function TRemoveSystemTypes.Execute(aText: TIDETextConverter): TModalResult;
|
|
var
|
|
Source: String;
|
|
Flags: TSrcEditSearchOptions;
|
|
Prompt: Boolean;
|
|
SearchFor: string;
|
|
i: Integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Source:=aText.Source;
|
|
|
|
Flags:=[sesoReplace,sesoReplaceAll,sesoRegExpr];
|
|
Prompt:=false;
|
|
SearchFor:='';
|
|
for i:=Low(PreDefinedH2PasTypes) to High(PreDefinedH2PasTypes) do begin
|
|
if SearchFor<>'' then
|
|
SearchFor:=SearchFor+'|';
|
|
SearchFor:=SearchFor
|
|
+'P'+PreDefinedH2PasTypes[i]+'\s*=\s*\^'+PreDefinedH2PasTypes[i];
|
|
end;
|
|
SearchFor:='^\s*('+SearchFor+');\s*$';
|
|
Result:=IDESearchInText('',Source,SearchFor,'',Flags,Prompt,nil);
|
|
if Result<>mrOk then begin
|
|
ErrorMsg := Format(h2pDeletionOfFailed, [SearchFor]);
|
|
exit;
|
|
end;
|
|
|
|
// replace NULL with nil
|
|
Flags:=[sesoReplace,sesoReplaceAll,sesoRegExpr,sesoMatchCase];
|
|
Result:=IDESearchInText('',Source,'\bNULL\b','nil',Flags,Prompt,nil);
|
|
if Result<>mrOk then begin
|
|
ErrorMsg := h2pReplacingOfNULLWithNilFailed;
|
|
exit;
|
|
end;
|
|
|
|
aText.Source:=Source;
|
|
end;
|
|
|
|
{ TRemoveRedefinedPointerTypes }
|
|
|
|
class function TRemoveRedefinedPointerTypes.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveRedefinedPointerTypes;
|
|
end;
|
|
|
|
function TRemoveRedefinedPointerTypes.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
{ search for
|
|
Pname = ^name;
|
|
if PName has a redefinition, delete the second one
|
|
}
|
|
var
|
|
Lines: TStrings;
|
|
i: Integer;
|
|
Line: string;
|
|
PointerName: String;
|
|
TypeName: String;
|
|
j: Integer;
|
|
Pattern: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Lines[i];
|
|
if REMatches(Line,'^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*\^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*;\s*($|//|/\*)') then begin
|
|
PointerName:=REVar(1);
|
|
TypeName:=REVar(2);
|
|
Pattern:='^\s*'+PointerName+'\s*=\s*\^\s*'+TypeName+'\s*;';
|
|
j:=Lines.Count-1;
|
|
while (j>i) do begin
|
|
if REMatches(Lines[j],Pattern) then
|
|
Lines.Delete(j);
|
|
dec(j);
|
|
end;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TRemoveEmptyTypeVarConstSections }
|
|
|
|
class function TRemoveEmptyTypeVarConstSections.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveEmptyTypeVarConstSections;
|
|
end;
|
|
|
|
function TRemoveEmptyTypeVarConstSections.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Src: String;
|
|
p: Integer;
|
|
AtomStart: Integer;
|
|
CurAtom, NextAtom: PChar;
|
|
KeyWordStart: LongInt;
|
|
KeyWordEnd: LongInt;
|
|
DeleteSection: Boolean;
|
|
Modified: Boolean;
|
|
begin
|
|
Result:=mrCancel;
|
|
Src:=aText.Source;
|
|
p:=1;
|
|
AtomStart:=p;
|
|
repeat
|
|
ReadRawNextPascalAtom(Src,p,AtomStart);
|
|
if p>length(Src) then break;
|
|
CurAtom:=@Src[AtomStart];
|
|
if (CompareIdentifiers(CurAtom,'type')=0)
|
|
or (CompareIdentifiers(CurAtom,'var')=0)
|
|
or (CompareIdentifiers(CurAtom,'const')=0)
|
|
or (CompareIdentifiers(CurAtom,'threadvar')=0)
|
|
or (CompareIdentifiers(CurAtom,'resourcestring')=0)
|
|
then begin
|
|
// start of a section found
|
|
// read next atoms to check if they are identifier plus definition operator
|
|
// 'name =' or 'name:' or 'name,'
|
|
KeyWordStart:=AtomStart;
|
|
KeyWordEnd:=p;
|
|
ReadRawNextPascalAtom(Src,p,AtomStart);
|
|
if p<length(Src) then begin
|
|
NextAtom:=@Src[AtomStart];
|
|
DeleteSection:=true;
|
|
if GetIdentLen(NextAtom)>0 then begin
|
|
ReadRawNextPascalAtom(Src,p,AtomStart);
|
|
if (p<=length(Src)) and (p-AtomStart=1)
|
|
and (Src[AtomStart] in ['=',':',',']) then
|
|
DeleteSection:=false;
|
|
end;
|
|
if DeleteSection then begin
|
|
// this section is empty -> delete it
|
|
Src:=copy(Src,1,KeyWordStart-1)+copy(Src,KeyWordEnd,length(Src));
|
|
Modified:=true;
|
|
// adjust position
|
|
p:=KeyWordStart;
|
|
end;
|
|
end;
|
|
end;
|
|
until false;
|
|
if Modified then
|
|
aText.Source:=Src;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
type
|
|
TImplicitType = class
|
|
public
|
|
Name: string;
|
|
Code: string;
|
|
MinPosition: integer;
|
|
MaxPosition: integer;
|
|
MinPositionNeedsTypeSection: boolean;
|
|
end;
|
|
|
|
function CompareImplicitTypeNames(Type1, Type2: Pointer): integer;
|
|
begin
|
|
Result:=CompareIdentifiers(PChar(TImplicitType(Type1).Name),
|
|
PChar(TImplicitType(Type2).Name));
|
|
end;
|
|
|
|
function CompareImplicitTypeStringAndName(Identifier,
|
|
ImplicitType: Pointer): integer;
|
|
begin
|
|
Result:=CompareIdentifiers(PChar(Identifier),
|
|
PChar(TImplicitType(ImplicitType).Name));
|
|
end;
|
|
|
|
function CompareImplicitTypeMinPositions(Type1, Type2: Pointer): integer;
|
|
begin
|
|
Result:=TImplicitType(Type1).MinPosition-TImplicitType(Type2).MinPosition;
|
|
end;
|
|
|
|
{ TReplaceImplicitParameterTypes }
|
|
|
|
class function TReplaceImplicitTypes.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pReplaceImplicitTypesForExampleProcedureProcNameAAr, [#13, #13, #13, #13, #13, #13]);
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.FindNextImplicitType(var Position: integer;
|
|
out aTypeStart, aTypeEnd: integer): boolean;
|
|
var
|
|
AtomStart: LongInt;
|
|
|
|
function ReadTilTypeEnd: boolean;
|
|
var
|
|
CurAtom: String;
|
|
begin
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then exit(false);
|
|
if (length(CurAtom)=1) and (CurAtom[1] in ['(','[']) then begin
|
|
// skip brackets
|
|
if not ReadTilPascalBracketClose(Src,Position) then exit(false);
|
|
end else if (length(CurAtom)=1) and (CurAtom[1] in [';',')',']'])
|
|
then begin
|
|
// type end found
|
|
aTypeEnd:=AtomStart;
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
until false;
|
|
end;
|
|
|
|
var
|
|
CurAtom: string;
|
|
begin
|
|
Result:=false;
|
|
aTypeStart:=0;
|
|
aTypeEnd:=0;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then break;
|
|
//DebugLn(['TReplaceImplicitTypes.FindNextImplicitType atom ',CurAtom]);
|
|
if CurAtom=':' then begin
|
|
// var, const, out declaration
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then break;
|
|
aTypeStart:=AtomStart;
|
|
if CompareIdentifiers(PChar(CurAtom),'array')=0 then begin
|
|
// :array
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then break;
|
|
if CurAtom='[' then begin
|
|
// :array[
|
|
if not ReadTilPascalBracketClose(Src,Position) then break;
|
|
// :array[..]
|
|
Result:=ReadTilTypeEnd;
|
|
exit;
|
|
end;
|
|
end
|
|
else if CompareIdentifiers(PChar(CurAtom),'function')=0 then begin
|
|
// :function
|
|
// for example: function hci_for_each_dev(func:function (dd:longint):longint):longint;
|
|
Result:=ReadTilTypeEnd;
|
|
exit;
|
|
end
|
|
else if CompareIdentifiers(PChar(CurAtom),'procedure')=0 then begin
|
|
// :procedure
|
|
// for example: procedure hci_for_each_dev(func:function (dd:longint):longint);
|
|
Result:=ReadTilTypeEnd;
|
|
exit;
|
|
end;
|
|
end;
|
|
until CurAtom='';
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.SearchImplicitParameterTypes(
|
|
var ModalResult: TModalResult): boolean;
|
|
var
|
|
Position: Integer;
|
|
StartPos, EndPos: integer;
|
|
TypeCode: String;
|
|
TypeName: String;
|
|
NewType: TImplicitType;
|
|
begin
|
|
Result:=false;
|
|
ModalResult:=mrCancel;
|
|
Position:=1;
|
|
while FindNextImplicitType(Position,StartPos,EndPos) do begin
|
|
TypeCode:=copy(Src,StartPos,EndPos-StartPos);
|
|
//DebugLn(['SearchImplicitParameterTypes ',StartPos,' TypeCode="',TypeCode,'"']);
|
|
TypeName:=CodeToIdentifier(TypeCode);
|
|
if TypeName='' then continue;
|
|
if (ImplicitTypes<>nil)
|
|
and (ImplicitTypes.FindKey(Pointer(TypeName),
|
|
@CompareImplicitTypeStringAndName)<>nil)
|
|
then begin
|
|
// type exists already
|
|
continue;
|
|
end;
|
|
// add new type
|
|
//DebugLn(['SearchImplicitParameterTypes Adding new type ',StartPos,' TypeName=',TypeName,' TypeCode="',TypeCode,'"']);
|
|
NewType:=TImplicitType.Create;
|
|
NewType.Name:=TypeName;
|
|
NewType.Code:=TypeCode;
|
|
NewType.MaxPosition:=StartPos;
|
|
if ImplicitTypes=nil then
|
|
ImplicitTypes:=TAVLTree.Create(@CompareImplicitTypeNames);
|
|
ImplicitTypes.Add(NewType);
|
|
end;
|
|
ModalResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.PosToStr(Position: integer): string;
|
|
var
|
|
Line, Col: integer;
|
|
begin
|
|
SrcPosToLineCol(Src,Position,Line,Col);
|
|
Result:='(y='+IntToStr(Line)+',x='+IntToStr(Col)+')';
|
|
end;
|
|
|
|
procedure TReplaceImplicitTypes.AdjustMinPositions(const Identifier: string);
|
|
var
|
|
Node: TAVLTreeNode;
|
|
Item: TImplicitType;
|
|
Position: Integer;
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
MinPos: LongInt;
|
|
begin
|
|
if TypeEnd>0 then
|
|
MinPos:=TypeEnd
|
|
else if ConstSectionEnd>0 then
|
|
MinPos:=ConstSectionEnd
|
|
else
|
|
exit;
|
|
//DebugLn(['AdjustMinPositions Identifier=',Identifier]);
|
|
|
|
// search Identifier in all implicit type definitions
|
|
Node:=ImplicitTypes.FindLowest;
|
|
while Node<>nil do begin
|
|
Item:=TImplicitType(Node.Data);
|
|
if Item.MaxPosition>=TypeEnd then begin
|
|
// search Identifier in Item.Code
|
|
Position:=1;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Item.Code,Position,AtomStart);
|
|
if CurAtom='' then break;
|
|
//DebugLn(['AdjustMinPositions ',Item.Name,' ',CurAtom]);
|
|
if CompareIdentifiers(PChar(Identifier),PChar(CurAtom))=0 then begin
|
|
// this implicit type depends on an explicit type defined
|
|
// prior in this source file
|
|
{DebugLn(['AdjustMinPositions "',Item.Name,'=',Item.Code,'"',
|
|
' depends on ',Identifier,
|
|
' defined at ',PosToStr(MinPos),
|
|
' as "',copy(Src,MinPos,30),'"']);}
|
|
if Item.MinPosition<MinPos then begin
|
|
Item.MinPosition:=MinPos;
|
|
Item.MinPositionNeedsTypeSection:=TypeEnd<1;
|
|
end;
|
|
break;
|
|
end;
|
|
until false;
|
|
end;
|
|
Node:=ImplicitTypes.FindSuccessor(Node);
|
|
end;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadWord(var Position: integer): boolean;
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
begin
|
|
AtomStart:=Position;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (CurAtom<>'') and IsIdentStartChar[CurAtom[1]] then
|
|
Result:=true
|
|
else begin
|
|
DebugLn(['ReadWord word not found at ',PosToStr(AtomStart)]);
|
|
Result:=false;
|
|
end;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadUntilAtom(var Position: integer;
|
|
const StopAtom: string; SkipBrackets: boolean = true): boolean;
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
StartPos: LongInt;
|
|
begin
|
|
Result:=false;
|
|
StartPos:=Position;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadUntilAtom atom not found: "',StopAtom,'" (starting at ',PosToStr(StartPos),')']);
|
|
exit;
|
|
end;
|
|
if SkipBrackets then begin
|
|
if CurAtom='(' then begin
|
|
// skip round bracket open
|
|
if not ReadUntilAtom(Position,')') then exit;
|
|
end else if CurAtom='[' then begin
|
|
// skip edged bracket open
|
|
if not ReadUntilAtom(Position,']') then exit;
|
|
end;
|
|
end;
|
|
until CurAtom=StopAtom;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadRecord(var Position: integer): boolean;
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
begin
|
|
Result:=false;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadRecord record end not found']);
|
|
exit;
|
|
end else if CurAtom='(' then begin
|
|
// skip round bracket open
|
|
if not ReadUntilAtom(Position,')') then exit;
|
|
end else if CurAtom='[' then begin
|
|
// skip edged bracket open
|
|
if not ReadUntilAtom(Position,']') then exit;
|
|
end else if CompareIdentifiers(PChar(CurAtom),'CASE')=0 then begin
|
|
// read identifier
|
|
if not ReadWord(Position) then exit;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
//DebugLn(['ReadRecord CASE colon or "of" CurAtom="',CurAtom,'"']);
|
|
if CurAtom=':' then begin
|
|
// read case type
|
|
if not ReadWord(Position) then begin
|
|
DebugLn(['ReadRecord missing case type at ',PosToStr(Position)]);
|
|
exit;
|
|
end;
|
|
// read 'of'
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadRecord missing "of" at ',PosToStr(Position)]);
|
|
exit;
|
|
end;
|
|
end;
|
|
if CompareIdentifiers(PChar(CurAtom),'OF')<>0 then begin
|
|
DebugLn(['ReadRecord record case "of" not found at ',PosToStr(AtomStart)]);
|
|
exit;
|
|
end;
|
|
end else if CurAtom=':' then begin
|
|
// skip type
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='(' then begin
|
|
// skip case brackets
|
|
if not ReadUntilAtom(Position,')') then exit;
|
|
end else begin
|
|
// read normal type
|
|
Position:=AtomStart;
|
|
if not ReadTypeDefinition(Position) then exit;
|
|
end;
|
|
end;
|
|
until CompareIdentifiers(PChar(CurAtom),'END')=0;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadClass(var Position: integer): boolean;
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
begin
|
|
//DebugLn(['ReadClass at ',PosToStr(Position)]);
|
|
Result:=false;
|
|
AtomStart:=Position;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
//DebugLn(['ReadClass first atom "',CurAtom,'"']);
|
|
if CurAtom=';' then begin
|
|
// this is a forward class definition
|
|
//DebugLn(['ReadClass forward defined class found']);
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
//DebugLn(['ReadClass CurAtom="',CurAtom,'"']);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadClass class end not found']);
|
|
exit;
|
|
end else if CurAtom='(' then begin
|
|
// skip round bracket open
|
|
if not ReadUntilAtom(Position,')') then exit;
|
|
end else if CurAtom='[' then begin
|
|
// skip edged bracket open
|
|
if not ReadUntilAtom(Position,']') then exit;
|
|
end else if CurAtom=':' then begin
|
|
// skip type
|
|
if not ReadTypeDefinition(Position) then exit;
|
|
end;
|
|
until CompareIdentifiers(PChar(CurAtom),'END')=0;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadTypeDefinition(
|
|
var Position: integer): boolean;
|
|
// Position must be after the colon
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
Enum: String;
|
|
begin
|
|
//DebugLn(['ReadTypeDefinition reading type definition at ',PosToStr(Position)]);
|
|
Result:=false;
|
|
AtomStart:=Position;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='(' then begin
|
|
// enumeration constants
|
|
//DebugLn(['ReadTypeDefinition enumeration found at ',PosToStr(AtomStart)]);
|
|
repeat
|
|
Enum:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (Enum='') then exit;// missing bracket close
|
|
if Enum=')' then exit(true);// type end found
|
|
if (not IsIdentStartChar[Enum[1]]) then exit;// enum missing
|
|
//DebugLn(['ReadTypeDefinition enum ',Enum,' found at ',PosToStr(AtomStart)]);
|
|
AdjustMinPositions(Enum);
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom=')' then exit(true);// type end found
|
|
if CurAtom<>',' then exit;// comma missing
|
|
until false;
|
|
end;
|
|
repeat
|
|
//DebugLn(['ReadTypeDefinition CurAtom="',CurAtom,'"']);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadTypeDefinition type end not found']);
|
|
exit;
|
|
end;
|
|
if IsIdentStartChar[CurAtom[1]] then begin
|
|
if CompareIdentifiers(PChar(CurAtom),'RECORD')=0 then begin
|
|
// skip record
|
|
Result:=ReadRecord(Position);
|
|
exit;
|
|
end;
|
|
if (CompareIdentifiers(PChar(CurAtom),'CLASS')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'OBJECT')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'INTERFACE')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'DISPINTERFACE')=0)
|
|
then begin
|
|
// skip record
|
|
Result:=ReadClass(Position);
|
|
exit;
|
|
end;
|
|
end else if CurAtom='(' then begin
|
|
// skip round bracket open
|
|
if not ReadUntilAtom(Position,')') then exit;
|
|
end else if CurAtom='[' then begin
|
|
// skip edged bracket open
|
|
if not ReadUntilAtom(Position,']') then exit;
|
|
end else if (length(CurAtom)=1) and (CurAtom[1] in [';',')',']']) then
|
|
break;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
until false;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.ReadConstSection(var Position: integer): boolean;
|
|
// Position must be after the 'const' keyword
|
|
var
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
ConstStart: LongInt;
|
|
begin
|
|
Result:=false;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then begin
|
|
DebugLn(['ReadConstSection end not found']);
|
|
exit;
|
|
end;
|
|
if IsIdentStartChar[CurAtom[1]] then begin
|
|
// const identifier(s) or end of const section
|
|
//DebugLn(['ReadConstSection Const name ',CurAtom,' at ',PosToStr(AtomStart)]);
|
|
ConstStart:=AtomStart;
|
|
// for example: a,b,c: integer = 1; d=1, e:integer=0;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (length(CurAtom)<>1) or (not (CurAtom[1] in [',','=',':'])) then
|
|
begin
|
|
// end of const section
|
|
Position:=ConstStart;
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
Position:=ConstStart;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
// read identifier
|
|
if (CurAtom<>'') and IsIdentStartChar[CurAtom[1]] then begin
|
|
// identifier
|
|
AdjustMinPositions(CurAtom);
|
|
end else begin
|
|
DebugLn(['ReadConstSection end of section missing']);
|
|
exit;
|
|
end;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (CurAtom='=') or (CurAtom=':') then begin
|
|
// skip type and expression
|
|
if not ReadUntilAtom(Position,';') then exit;
|
|
break;
|
|
end else if CurAtom=',' then begin
|
|
// next const name
|
|
end else begin
|
|
DebugLn(['ReadConstSection end of section missing']);
|
|
exit;
|
|
end;
|
|
until false;
|
|
end else begin
|
|
// end of const section
|
|
break;
|
|
end;
|
|
until false;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.FindExplicitTypesAndConstants(
|
|
var ModalResult: TModalResult): boolean;
|
|
{ every implicit type can contain references to explicit types and constants
|
|
For example: array[0..3] of bogus
|
|
If 'bogus' is defined in this source, then the new type must be defined
|
|
after 'bogus'.
|
|
=> Search all explicit types
|
|
}
|
|
var
|
|
Position: Integer;
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
Identifier: String;
|
|
TypeDefStart: LongInt;
|
|
ErrLine: integer;
|
|
ErrCol: integer;
|
|
begin
|
|
Result:=false;
|
|
ModalResult:=mrCancel;
|
|
|
|
Position:=1;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
//DebugLn(['FindExplicitTypes CurAtom="',CurAtom,'"']);
|
|
if CurAtom='' then break;
|
|
if CompareIdentifiers(PChar(CurAtom),'type')=0 then begin
|
|
// type section found
|
|
//DebugLn(['FindExplicitTypes type section found at ',PosToStr(AtomStart)]);
|
|
repeat
|
|
Identifier:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (Identifier<>'') and (IsIdentStartChar[Identifier[1]]) then begin
|
|
// word found (can be an identifier or start of next section)
|
|
TypeStart:=AtomStart;
|
|
TypeEnd:=0;
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom<>'=' then begin
|
|
//DebugLn(['FindExplicitTypes type section ended at ',PosToStr(AtomStart)]);
|
|
break;
|
|
end;
|
|
// Identifier is a type => find end of type definition
|
|
//DebugLn(['FindExplicitTypes type definition found: ',Identifier,' at ',PosToStr(TypeStart)]);
|
|
TypeDefStart:=Position;
|
|
Result:=ReadTypeDefinition(Position);
|
|
if not Result then begin
|
|
SrcPosToLineCol(Src,TypeStart,ErrLine,ErrCol);
|
|
ErrorColumn:=ErrCol;
|
|
ErrorLine:=ErrLine;
|
|
ErrorMsg := Format(h2pFindExplicitTypesFAILEDReadingTypeDefinition, [Identifier]);
|
|
DebugLn(['FindExplicitTypes FAILED reading type definition ',Identifier,' at ',PosToStr(TypeStart)]);
|
|
exit;
|
|
end;
|
|
TypeEnd:=Position;
|
|
// add the semicolon, if not already done
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom=';' then
|
|
TypeEnd:=Position;
|
|
// adjust implicit identifiers
|
|
AdjustMinPositions(Identifier);
|
|
// reread the type for the enums
|
|
Position:=TypeDefStart;
|
|
//DebugLn(['FindExplicitTypes Rereading type definition ',Identifier,' at ',PosToStr(TypeStart)]);
|
|
Result:=ReadTypeDefinition(Position);
|
|
if not Result then begin
|
|
SrcPosToLineCol(Src,TypeStart,ErrLine,ErrCol);
|
|
ErrorColumn:=ErrCol;
|
|
ErrorLine:=ErrLine;
|
|
ErrorMsg := Format(h2pFindExplicitTypesFAILEDRereadingTypeDefinition, [Identifier]);
|
|
DebugLn(['FindExplicitTypes FAILED Rereading type definition ',Identifier,' at ',PosToStr(TypeStart)]);
|
|
exit;
|
|
end;
|
|
// skip semicolon
|
|
Position:=TypeEnd;
|
|
TypeEnd:=0;
|
|
end;
|
|
until false;
|
|
end
|
|
else if CompareIdentifiers(PChar(CurAtom),'const')=0 then begin
|
|
ConstSectionStart:=Position;
|
|
ConstSectionEnd:=0;
|
|
// find end of const section
|
|
//DebugLn(['TReplaceImplicitTypes.FindExplicitTypesAndConstants finding end of const section ...']);
|
|
Result:=ReadConstSection(Position);
|
|
if not Result then begin
|
|
SrcPosToLineCol(Src,ConstSectionStart,ErrLine,ErrCol);
|
|
ErrorColumn:=ErrCol;
|
|
ErrorLine:=ErrLine;
|
|
ErrorMsg := h2pFindExplicitTypesFAILEDReadingConstSection;
|
|
DebugLn(['FindExplicitTypes FAILED reading const section at ',PosToStr(ConstSectionStart)]);
|
|
exit;
|
|
end;
|
|
ConstSectionEnd:=Position;
|
|
// reread the section for the identifiers
|
|
Position:=ConstSectionStart;
|
|
//DebugLn(['TReplaceImplicitTypes.FindExplicitTypesAndConstants collecting const identifiers ...']);
|
|
Result:=ReadConstSection(Position);
|
|
if not Result then begin
|
|
SrcPosToLineCol(Src,ConstSectionStart,ErrLine,ErrCol);
|
|
ErrorColumn:=ErrCol;
|
|
ErrorLine:=ErrLine;
|
|
ErrorMsg := h2pFindExplicitTypesFAILEDReadingConstSection;
|
|
DebugLn(['FindExplicitTypes FAILED reading const section at ',PosToStr(ConstSectionStart)]);
|
|
exit;
|
|
end;
|
|
ConstSectionEnd:=0;
|
|
end;
|
|
until false;
|
|
|
|
ModalResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.InsertNewTypes(var ModalResult: TModalResult
|
|
): boolean;
|
|
|
|
function CreateCode(Item: TImplicitType): string;
|
|
begin
|
|
Result:=' '+Item.Name+' = '+Item.Code+';';
|
|
end;
|
|
|
|
var
|
|
Node: TAVLTreeNode;
|
|
Item: TImplicitType;
|
|
InsertPos: integer;
|
|
NextItem: TImplicitType;
|
|
NextInsertPos: integer;
|
|
NewCode: String;
|
|
begin
|
|
Result:=false;
|
|
ModalResult:=mrCancel;
|
|
if (ImplicitTypes<>nil) then begin
|
|
// re-sort the ImplicitTypes for MinPosition
|
|
ImplicitTypes.OnCompare:=@CompareImplicitTypeMinPositions;
|
|
try
|
|
// Insert every type
|
|
Node:=ImplicitTypes.FindHighest;
|
|
while Node<>nil do begin
|
|
Item:=TImplicitType(Node.Data);
|
|
NewCode:=CreateCode(Item);
|
|
if Item.MinPositionNeedsTypeSection or (Item.MinPosition=0) then
|
|
NewCode:='type'+LineEnding+NewCode;
|
|
InsertPos:=FindInsertPosition(Item.MinPosition);
|
|
// add all items at the same position
|
|
repeat
|
|
Node:=ImplicitTypes.FindPrecessor(Node);
|
|
if (Node=nil) then break;
|
|
NextItem:=TImplicitType(Node.Data);
|
|
NextInsertPos:=FindLineEndOrCodeAfterPosition(Src,NextItem.MinPosition,
|
|
length(Src)+1,false);
|
|
if InsertPos>NextInsertPos then
|
|
break;
|
|
NewCode:=NewCode+LineEnding+CreateCode(NextItem);
|
|
until false;
|
|
|
|
// insert line ends
|
|
if (InsertPos>1) and (InsertPos<length(Src))
|
|
and (not (Src[InsertPos-1] in [#10,#13])) then
|
|
NewCode:=LineEnding+NewCode;
|
|
if (InsertPos<=length(Src)) and (not (Src[InsertPos] in [#10,#13])) then
|
|
NewCode:=NewCode+LineEnding;
|
|
|
|
// insert code
|
|
DebugLn(['TReplaceImplicitTypes.InsertNewTypes Insert at ',PosToStr(InsertPos),' NewCode="',NewCode,'"']);
|
|
Src:=copy(Src,1,InsertPos-1)+NewCode+copy(Src,InsertPos,length(Src));
|
|
end;
|
|
finally
|
|
// re-sort the ImplicitTypes for Names
|
|
ImplicitTypes.OnCompare:=@CompareImplicitTypeNames;
|
|
end;
|
|
end;
|
|
ModalResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.FindInsertPosition(MinPos: integer): integer;
|
|
var
|
|
Position: Integer;
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
begin
|
|
if MinPos>0 then begin
|
|
Result:=FindLineEndOrCodeAfterPosition(Src,MinPos,length(Src)+1,false);
|
|
end else begin
|
|
// find insert position for a first type section
|
|
Result:=1;
|
|
Position:=1;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if CurAtom='' then break;
|
|
if (CompareIdentifiers(PChar(CurAtom),'UNIT')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'PROGRAM')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'LIBRARY')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'PACKAGE')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'USES')=0)
|
|
then begin
|
|
ReadUntilAtom(Position,';');
|
|
Result:=Position;
|
|
end
|
|
else if (CompareIdentifiers(PChar(CurAtom),'INTERFACE')=0)
|
|
or (CompareIdentifiers(PChar(CurAtom),'IMPLEMENTATION')=0)
|
|
then begin
|
|
Result:=Position;
|
|
// skip uses section
|
|
CurAtom:=ReadNextPascalAtom(Src,Position,AtomStart);
|
|
if (CurAtom<>'')
|
|
and (CompareIdentifiers(PChar(CurAtom),'USES')=0) then begin
|
|
ReadUntilAtom(Position,';');
|
|
Result:=Position;
|
|
end;
|
|
break;
|
|
end else
|
|
break;
|
|
until false;
|
|
end;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.UseNewTypes(var ModalResult: TModalResult
|
|
): boolean;
|
|
var
|
|
Position: Integer;
|
|
StartPos: Integer;
|
|
EndPos: Integer;
|
|
TypeCode: String;
|
|
TypeName: String;
|
|
Node: TAVLTreeNode;
|
|
Item: TImplicitType;
|
|
begin
|
|
Result:=false;
|
|
ModalResult:=mrCancel;
|
|
if (ImplicitTypes<>nil) then begin
|
|
Position:=1;
|
|
StartPos:=1;
|
|
EndPos:=1;
|
|
while FindNextImplicitType(Position,StartPos,EndPos) do begin
|
|
TypeCode:=copy(Src,StartPos,EndPos-StartPos);
|
|
//DebugLn(['UseNewTypes ',StartPos,' TypeCode="',TypeCode,'"']);
|
|
TypeName:=CodeToIdentifier(TypeCode);
|
|
if TypeName='' then continue;
|
|
Node:=ImplicitTypes.FindKey(Pointer(TypeName),
|
|
@CompareImplicitTypeStringAndName);
|
|
if Node<>nil then begin
|
|
// replace
|
|
Item:=TImplicitType(Node.Data);
|
|
Src:=copy(Src,1,StartPos-1)+Item.Name+copy(Src,EndPos,length(Src));
|
|
Position:=StartPos+length(Item.Name);
|
|
end;
|
|
end;
|
|
end;
|
|
ModalResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Src:=aText.Source;
|
|
if Src='' then exit(mrOk);
|
|
|
|
ImplicitTypes:=nil;
|
|
ExplicitTypes:=nil;
|
|
TypeEnd:=0;
|
|
ConstSectionEnd:=0;
|
|
try
|
|
if not SearchImplicitParameterTypes(Result) then exit;
|
|
if (ImplicitTypes<>nil) then begin
|
|
if not FindExplicitTypesAndConstants(Result) then exit;
|
|
if not InsertNewTypes(Result) then exit;
|
|
if not UseNewTypes(Result) then exit;
|
|
aText.Source:=Src;
|
|
end;
|
|
finally
|
|
if ImplicitTypes<>nil then begin
|
|
ImplicitTypes.FreeAndClear;
|
|
ImplicitTypes.Free;
|
|
end;
|
|
if ExplicitTypes<>nil then begin
|
|
ExplicitTypes.FreeAndClear;
|
|
ExplicitTypes.Free;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
function TReplaceImplicitTypes.CodeToIdentifier(const Code: string): string;
|
|
// for example:
|
|
// array[0..3] of integer -> TArray0to3OfInteger
|
|
var
|
|
Position: Integer;
|
|
AtomStart: LongInt;
|
|
CurAtom: String;
|
|
i: Integer;
|
|
begin
|
|
Result:='T';
|
|
Position:=1;
|
|
AtomStart:=Position;
|
|
repeat
|
|
CurAtom:=ReadNextPascalAtom(Code,Position,AtomStart);
|
|
if CurAtom='' then exit;
|
|
if CurAtom='..' then
|
|
// range
|
|
Result:=Result+'to'
|
|
else if IsIdentStartChar[CurAtom[1]] then
|
|
// word
|
|
Result:=Result+upCase(CurAtom[1])+copy(CurAtom,2,length(CurAtom))
|
|
else begin
|
|
// otherwise: add word and number characters
|
|
for i:=1 to length(CurAtom) do begin
|
|
case CurAtom[i] of
|
|
'0'..'9','_','a'..'z','A'..'Z': Result:=Result+CurAtom[i];
|
|
'.': Result:=Result+'.';
|
|
end;
|
|
end;
|
|
end;
|
|
if length(Result)>200 then begin
|
|
Result:=copy(Result,1,200);
|
|
exit;
|
|
end;
|
|
until false;
|
|
end;
|
|
|
|
{ TFixArrayOfParameterType }
|
|
|
|
class function TFixArrayOfParameterType.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pFixOpenArraysReplaceArrayOfWithArrayOfConst, [#13]);
|
|
end;
|
|
|
|
function TFixArrayOfParameterType.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
{ search for
|
|
array of )
|
|
and replace it with
|
|
array of const)
|
|
}
|
|
var
|
|
Lines: TStrings;
|
|
i: Integer;
|
|
Line: string;
|
|
MatchPos: integer;
|
|
MatchLen: integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Lines[i];
|
|
if REMatches(Line,'array of *\)','I') then begin
|
|
REVarPos(0,MatchPos,MatchLen);
|
|
Lines[i]:=copy(Line,1,MatchPos-1)+'array of const)'
|
|
+copy(Line,MatchPos+MatchLen,length(Line));
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TH2PasFileCInclude }
|
|
|
|
procedure TH2PasFileCInclude.SetFilename(const AValue: string);
|
|
begin
|
|
if FFilename=AValue then exit;
|
|
FFilename:=AValue;
|
|
end;
|
|
|
|
procedure TH2PasFileCInclude.SetH2PasFile(const AValue: TH2PasFile);
|
|
begin
|
|
if FH2PasFile=AValue then exit;
|
|
if (FH2PasFile<>nil) then
|
|
FH2PasFile.InternalRemoveCIncludedBy(Self);
|
|
FH2PasFile:=AValue;
|
|
if (FH2PasFile<>nil) then
|
|
FH2PasFile.InternalAddCIncludedBy(Self);
|
|
end;
|
|
|
|
procedure TH2PasFileCInclude.SetSrcFilename(const AValue: string);
|
|
begin
|
|
if FSrcFilename=AValue then exit;
|
|
FSrcFilename:=AValue;
|
|
FFilename:='';
|
|
end;
|
|
|
|
procedure TH2PasFileCInclude.SetSrcPos(const AValue: TPoint);
|
|
begin
|
|
FSrcPos:=AValue;
|
|
end;
|
|
|
|
constructor TH2PasFileCInclude.Create(TheOwner: TH2PasFile);
|
|
begin
|
|
FOwner:=TheOwner;
|
|
end;
|
|
|
|
destructor TH2PasFileCInclude.Destroy;
|
|
begin
|
|
H2PasFile:=nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TRemoveRedefinitionsInUnit }
|
|
|
|
class function TRemoveRedefinitionsInUnit.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveRedefinitionsInPascalUnit;
|
|
end;
|
|
|
|
function TRemoveRedefinitionsInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
//DebugLn(['TRemoveRedefinitionsInUnit.Execute START ',aText.Source]);
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TRemoveRedefinitionsInUnit.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.RemoveAllRedefinitions(TCodeBuffer(aText.CodeBuffer)) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TRemoveRedefinitionsInUnit.Execute RemoveAllRedefinitions failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
//DebugLn(['TRemoveRedefinitionsInUnit.Execute END ',aText.Source]);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TFixAliasDefinitionsInUnit }
|
|
|
|
class function TFixAliasDefinitionsInUnit.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pFixesSectionTypeOfAliasDefinitionsInPascalUnitChec, [#13, #13, #13]);
|
|
end;
|
|
|
|
function TFixAliasDefinitionsInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TFixAliasDefinitionsInUnit.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.FixAllAliasDefinitions(TCodeBuffer(aText.CodeBuffer)) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TFixAliasDefinitionsInUnit.Execute FixAllAliasDefinitions failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TFixH2PasMissingIFDEFsInUnit }
|
|
|
|
class function TFixH2PasMissingIFDEFsInUnit.ClassDescription: string;
|
|
begin
|
|
Result := h2pAddMissingH2pasIFDEFsForFunctionBodies;
|
|
end;
|
|
|
|
function TFixH2PasMissingIFDEFsInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Code: TCodeBuffer;
|
|
Changed: Boolean;
|
|
begin
|
|
Result:=mrCancel;
|
|
Changed:=false;
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
if not CodeToolBoss.FixMissingH2PasDirectives(Code,Changed) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TFixH2PasMissingIFDEFsInUnit.Execute failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TReduceCompilerDirectivesInUnit }
|
|
|
|
procedure TReduceCompilerDirectivesInUnit.SetDefines(const AValue: TStrings);
|
|
begin
|
|
if FDefines=AValue then exit;
|
|
FDefines.Assign(AValue);
|
|
end;
|
|
|
|
procedure TReduceCompilerDirectivesInUnit.SetUndefines(const AValue: TStrings);
|
|
begin
|
|
if FUndefines=AValue then exit;
|
|
FUndefines.Assign(AValue);
|
|
end;
|
|
|
|
constructor TReduceCompilerDirectivesInUnit.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FUndefines:=TStringList.Create;
|
|
FDefines:=TStringList.Create;
|
|
end;
|
|
|
|
destructor TReduceCompilerDirectivesInUnit.Destroy;
|
|
begin
|
|
FreeAndNil(FUndefines);
|
|
FreeAndNil(FDefines);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TReduceCompilerDirectivesInUnit.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pReduceCompilerDirectivesInPascalFileShortensExpres, [#13, #13]);
|
|
end;
|
|
|
|
function TReduceCompilerDirectivesInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Changed: Boolean;
|
|
Code: TCodeBuffer;
|
|
begin
|
|
Result:=mrCancel;
|
|
Changed:=false;
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
if not CodeToolBoss.ReduceCompilerDirectives(Code,Undefines,Defines,Changed)
|
|
then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TReduceCompilerDirectivesInUnit.Execute failed ',ErrorMsg]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TReplaceConstFunctionsInUnit }
|
|
|
|
class function TReplaceConstFunctionsInUnit.ClassDescription: string;
|
|
begin
|
|
Result := h2pReplaceSimpleFunctionsWithConstants;
|
|
end;
|
|
|
|
function TReplaceConstFunctionsInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TReplaceConstFunctionsInUnit.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.ReplaceAllConstFunctions(TCodeBuffer(aText.CodeBuffer)) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TReplaceConstFunctionsInUnit.Execute ReplaceAllConstFunctions failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TReplaceTypeCastFunctionsInUnit }
|
|
|
|
class function TReplaceTypeCastFunctionsInUnit.ClassDescription: string;
|
|
begin
|
|
Result := h2pReplaceSimpleFunctionsWithTypeCasts;
|
|
end;
|
|
|
|
function TReplaceTypeCastFunctionsInUnit.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TReplaceTypeCastFunctionsInUnit.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.ReplaceAllTypeCastFunctions(TCodeBuffer(aText.CodeBuffer)) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TReplaceTypeCastFunctionsInUnit.Execute ReplaceAllTypeCastFunctions failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TPreH2PasTools }
|
|
|
|
constructor TPreH2PasTools.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FOptions:=DefaultPreH2PasToolsOptions;
|
|
end;
|
|
|
|
class function TPreH2PasTools.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pPreH2PasASetOfCommonToolsToRunBeforeH2pasPhRemoveC, [#13, #13, #13, #13, #13, #13, #13, #13, #13])
|
|
;
|
|
end;
|
|
|
|
function TPreH2PasTools.Execute(aText: TIDETextConverter): TModalResult;
|
|
|
|
function Run(Option: TPreH2PasToolsOption;
|
|
ToolClass: TCustomTextConverterToolClass;
|
|
out aResult: TModalResult): boolean;
|
|
var
|
|
Tool: TCustomTextConverterTool;
|
|
begin
|
|
Result:=true;
|
|
aResult:=mrOk;
|
|
if not (Option in Options) then exit;
|
|
DebugLn(['TPreH2PasTools.Execute.Run ',ToolClass.ClassName]);
|
|
Tool:=ToolClass.Create(nil);
|
|
try
|
|
Tool.ClearError;
|
|
aResult:=Tool.Execute(aText);
|
|
if aResult<>mrOk then begin
|
|
AssignError(Tool);
|
|
DebugLn(['TPreH2PasTools.Execute.Run failed: ',ToolClass.ClassName]);
|
|
exit(false);
|
|
end;
|
|
finally
|
|
Tool.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not Run(phRemoveCPlusPlusExternCTool,
|
|
TRemoveCPlusPlusExternCTool,Result) then exit;
|
|
if not Run(phRemoveEmptyCMacrosTool,
|
|
TRemoveEmptyCMacrosTool,Result) then exit;
|
|
if not Run(phReplaceEdgedBracketPairWithStar,
|
|
TReplaceEdgedBracketPairWithStar,Result) then exit;
|
|
if not Run(phReplaceMacro0PointerWithNULL,
|
|
TReplaceMacro0PointerWithNULL,Result) then exit;
|
|
if not Run(phConvertFunctionTypesToPointers,
|
|
TConvertFunctionTypesToPointers,Result) then exit;
|
|
if not Run(phConvertEnumsToTypeDef,
|
|
TConvertEnumsToTypeDef,Result) then exit;
|
|
if not Run(phCommentComplexCMacros,
|
|
TCommentComplexCMacros,Result) then exit;
|
|
if not Run(phCommentComplexCFunctions,
|
|
TCommentComplexCFunctions,Result) then exit;
|
|
if not Run(phAddMissingMacroBrackets,
|
|
TAddMissingMacroBrackets,Result) then exit;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TPostH2PasTools }
|
|
|
|
procedure TPostH2PasTools.SetDefines(const AValue: TStrings);
|
|
begin
|
|
if FDefines=AValue then exit;
|
|
FDefines.Assign(AValue);
|
|
end;
|
|
|
|
procedure TPostH2PasTools.SetUndefines(const AValue: TStrings);
|
|
begin
|
|
if FUndefines=AValue then exit;
|
|
FUndefines.Assign(AValue);
|
|
end;
|
|
|
|
procedure TPostH2PasTools.SetUseUnits(const AValue: TStrings);
|
|
begin
|
|
if FUseUnits=AValue then exit;
|
|
FUseUnits.Assign(FUseUnits);
|
|
end;
|
|
|
|
constructor TPostH2PasTools.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FDefines:=TStringList.Create;
|
|
FUndefines:=TStringList.Create;
|
|
FUseUnits:=TStringList.Create;
|
|
FOptions:=DefaultPostH2PasToolsOptions;
|
|
end;
|
|
|
|
destructor TPostH2PasTools.Destroy;
|
|
begin
|
|
FreeAndNil(FDefines);
|
|
FreeAndNil(FUndefines);
|
|
FreeAndNil(FUseUnits);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TPostH2PasTools.ClassDescription: string;
|
|
begin
|
|
Result := Format(h2pPostH2PasASetOfCommonToolsToRunAfterH2pasPhReplace, [#13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13, #13])
|
|
;
|
|
end;
|
|
|
|
function TPostH2PasTools.Execute(aText: TIDETextConverter): TModalResult;
|
|
|
|
function Run(Option: TPostH2PasToolsOption;
|
|
ToolClass: TCustomTextConverterToolClass;
|
|
var aResult: TModalResult): boolean;
|
|
var
|
|
Tool: TCustomTextConverterTool;
|
|
begin
|
|
Result:=true;
|
|
aResult:=mrOk;
|
|
if not (Option in Options) then exit;
|
|
DebugLn(['TPostH2PasTools.Execute.Run ',ToolClass.ClassName]);
|
|
Tool:=ToolClass.Create(nil);
|
|
try
|
|
Tool.ClearError;
|
|
aResult:=Tool.Execute(aText);
|
|
if aResult<>mrOk then begin
|
|
AssignError(Tool);
|
|
DebugLn(['TPostH2PasTools.Execute.Run failed: ',ToolClass.ClassName]);
|
|
exit(false);
|
|
end;
|
|
finally
|
|
Tool.Free;
|
|
end;
|
|
end;
|
|
|
|
function ReduceCompilerDirectives(var Changed: boolean;
|
|
var aResult: TModalResult): boolean;
|
|
var
|
|
Code: TCodeBuffer;
|
|
begin
|
|
aResult:=mrOk;
|
|
if not (phReduceCompilerDirectivesInUnit in Options) then exit;
|
|
DebugLn(['TPostH2PasTools.Execute.ReduceCompilerDirectives ']);
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
if not CodeToolBoss.ReduceCompilerDirectives(Code,Undefines,Defines,Changed)
|
|
then begin
|
|
DebugLn(['TPostH2PasTools.Execute.ReduceCompilerDirectives failed']);
|
|
AssignCodeToolBossError;
|
|
aResult:=mrCancel;
|
|
exit(false);
|
|
end;
|
|
aResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function AddToUsesSection(var Changed: boolean;
|
|
var aResult: TModalResult): boolean;
|
|
var
|
|
i: Integer;
|
|
UnitName: string;
|
|
begin
|
|
aResult:=mrOk;
|
|
if not (phAddUnitsToUsesSection in Options) then exit;
|
|
DebugLn(['TPostH2PasTools.Execute.AddToUsesSection ']);
|
|
for i:=0 to FUseUnits.Count-1 do begin
|
|
UnitName:=FUseUnits[i];
|
|
if (UnitName='') then continue;
|
|
if not IsValidIdent(UnitName) then
|
|
raise Exception.Create(Format(h2pTPostH2PasToolsExecuteAddToUsesSectionInvalidUnitn, [UnitName]));
|
|
Changed:=true;
|
|
if not CodeToolBoss.AddUnitToMainUsesSection(TCodeBuffer(aText.CodeBuffer),UnitName,'')
|
|
then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TPostH2PasTools.Execute.AddToUsesSection failed ',CodeToolBoss.ErrorMessage]);
|
|
aResult:=mrCancel;
|
|
exit(false);
|
|
end;
|
|
end;
|
|
aResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function ConvertSimpleFunctions(var Changed: boolean;
|
|
var aResult: TModalResult): boolean;
|
|
var
|
|
Code: TCodeBuffer;
|
|
OldChangeStep: LongInt;
|
|
begin
|
|
aResult:=mrOk;
|
|
OldChangeStep:=CodeToolBoss.ChangeStep;
|
|
if (phReplaceConstFunctionsInUnit in Options) then begin
|
|
DebugLn(['TPostH2PasTools.Execute ReplaceAllConstFunctions ']);
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
if not CodeToolBoss.ReplaceAllConstFunctions(Code) then begin
|
|
DebugLn(['ReplaceAllConstFunctions failed']);
|
|
AssignCodeToolBossError;
|
|
aResult:=mrCancel;
|
|
exit(false);
|
|
end;
|
|
end;
|
|
if (phReplaceTypeCastFunctionsInUnit in Options) then begin
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
DebugLn(['TPostH2PasTools.Execute ReplaceAllTypeCastFunctions ']);
|
|
if not CodeToolBoss.ReplaceAllTypeCastFunctions(Code) then begin
|
|
DebugLn(['ReplaceAllTypeCastFunctions failed']);
|
|
AssignCodeToolBossError;
|
|
aResult:=mrCancel;
|
|
exit(false);
|
|
end;
|
|
end;
|
|
if OldChangeStep<>CodeToolBoss.ChangeStep then
|
|
Changed:=true;
|
|
aResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
function FixAliasDefinitions(var Changed: boolean;
|
|
var aResult: TModalResult): boolean;
|
|
var
|
|
Code: TCodeBuffer;
|
|
OldChangeStep: LongInt;
|
|
begin
|
|
aResult:=mrOk;
|
|
OldChangeStep:=CodeToolBoss.ChangeStep;
|
|
if (phFixAliasDefinitionsInUnit in Options) then begin
|
|
DebugLn(['TPostH2PasTools.Execute FixAllAliasDefinitions ']);
|
|
Code:=TCodeBuffer(aText.CodeBuffer);
|
|
if not CodeToolBoss.FixAllAliasDefinitions(Code) then begin
|
|
DebugLn(['FixAliasDefinitions failed']);
|
|
AssignCodeToolBossError;
|
|
aResult:=mrCancel;
|
|
exit(false);
|
|
end;
|
|
end;
|
|
if OldChangeStep<>CodeToolBoss.ChangeStep then
|
|
Changed:=true;
|
|
aResult:=mrOk;
|
|
Result:=true;
|
|
end;
|
|
|
|
var
|
|
Changed: boolean;
|
|
begin
|
|
Result:=mrOk;
|
|
Changed:=false;
|
|
// basic h2pas fixes (unit name, system types, missing IFDEFs)
|
|
if not Run(phReplaceUnitFilenameWithUnitName,
|
|
TReplaceUnitFilenameWithUnitName,Result) then exit;
|
|
if not Run(phRemoveIncludeDirectives,
|
|
TRemoveIncludeDirectives,Result) then exit;
|
|
if not Run(phRemoveDoubleSemicolons,
|
|
TRemoveDoubleSemicolons,Result) then exit;
|
|
if not Run(phRemoveSystemTypes,
|
|
TRemoveSystemTypes,Result) then exit;
|
|
if not Run(phFixH2PasMissingIFDEFsInUnit,
|
|
TFixH2PasMissingIFDEFsInUnit,Result) then exit;
|
|
// reduce compiler directives so that other tools can work with less double data
|
|
if not ReduceCompilerDirectives(Changed,Result) then exit;
|
|
// remove h2pas redefinitions to get unambiguous types
|
|
if not Run(phRemoveRedefinedPointerTypes,
|
|
TRemoveRedefinedPointerTypes,Result) then exit;
|
|
if not Run(phRemoveEmptyTypeVarConstSections,
|
|
TRemoveEmptyTypeVarConstSections,Result) then exit;
|
|
// add / replace implicit types, not converted by h2pas
|
|
if not Run(phReplaceImplicitTypes,
|
|
TReplaceImplicitTypes,Result) then exit;
|
|
if not Run(phFixArrayOfParameterType,
|
|
TFixArrayOfParameterType,Result) then exit;
|
|
if not Run(phAddMissingPointerTypes,
|
|
TAddMissingPointerTypes,Result) then exit;
|
|
// remove redefinitions, to get unambiguous types
|
|
if not Run(phRemoveRedefinitionsInUnit,
|
|
TRemoveRedefinitionsInUnit,Result) then exit;
|
|
|
|
// optimization
|
|
repeat
|
|
Changed:=false;
|
|
if not ReduceCompilerDirectives(Changed,Result) then exit;
|
|
if not FixAliasDefinitions(Changed,Result) then exit;
|
|
if not ConvertSimpleFunctions(Changed,Result) then exit;
|
|
until Changed=false;
|
|
|
|
// fix forward definitions
|
|
if not Run(phFixForwardDefinitions,
|
|
TFixForwardDefinitions,Result) then exit;
|
|
// add units to uses section
|
|
if not AddToUsesSection(Changed,Result) then exit;
|
|
end;
|
|
|
|
{ TRemoveIncludeDirectives }
|
|
|
|
class function TRemoveIncludeDirectives.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveAllIncludeDirectives;
|
|
end;
|
|
|
|
constructor TRemoveIncludeDirectives.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
SearchFor:='\{\$(include|i)\b.*\}';
|
|
ReplaceWith:='';
|
|
Options:=Options+[trtRegExpr];
|
|
end;
|
|
|
|
{ TConvertFunctionTypesToPointers }
|
|
|
|
class function TConvertFunctionTypesToPointers.ClassDescription: string;
|
|
begin
|
|
Result := h2pConvertFunctionTypesToPointers;
|
|
end;
|
|
|
|
function TConvertFunctionTypesToPointers.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Src: String;
|
|
SrcLen: Integer;
|
|
FuncTypes: TAVLTree; // tree of TImplicitType
|
|
|
|
procedure CheckTypeDef(var p: integer);
|
|
// Check if it is: typedef identifier ( funcname ) (
|
|
var
|
|
StartPos: LongInt;
|
|
EndPos: LongInt;
|
|
NewType: TImplicitType;
|
|
begin
|
|
// typedef found
|
|
inc(p,length('typedef'));
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
// skip identifier
|
|
if not IsIdentStartChar[Src[p]] then exit;
|
|
while (p<SrcLen) and IsIdentChar[Src[p]] do inc(p);
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
// skip (
|
|
if Src[p]<>'(' then exit;
|
|
inc(p);
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
if p>=SrcLen then exit;
|
|
// read name of function type
|
|
StartPos:=p;
|
|
if not IsIdentStartChar[Src[p]] then exit;
|
|
while (p<SrcLen) and IsIdentChar[Src[p]] do inc(p);
|
|
EndPos:=p;
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
if p>=SrcLen then exit;
|
|
// skip )
|
|
if Src[p]<>')' then exit;
|
|
inc(p);
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
if p>=SrcLen then exit;
|
|
// skip (
|
|
if Src[p]<>'(' then exit;
|
|
// function type found
|
|
NewType:=TImplicitType.Create;
|
|
NewType.Name:=copy(Src,StartPos,EndPos-StartPos);
|
|
writeln('TConvertFunctionTypesToPointers.Execute.CheckType function type found Name=',NewType.Name);
|
|
if FuncTypes=nil then
|
|
FuncTypes:=TAVLTree.Create(@CompareImplicitTypeNames);
|
|
FuncTypes.Add(NewType);
|
|
// add * in front of name
|
|
System.Insert('*',Src,StartPos);
|
|
SrcLen:=length(Src);
|
|
end;
|
|
|
|
procedure CheckIdentifier(var p: integer);
|
|
var
|
|
IdentPos: LongInt;
|
|
IdentEnd: LongInt;
|
|
begin
|
|
IdentPos:=p;
|
|
// skip identifier
|
|
while (p<=SrcLen) and IsIdentChar[Src[p]] do inc(p);
|
|
if FuncTypes.FindKey(@Src[IdentPos],@CompareImplicitTypeStringAndName)=nil
|
|
then
|
|
exit;
|
|
// this identifier is a function type
|
|
IdentEnd:=p;
|
|
// skip space
|
|
while (p<SrcLen) and IsSpaceChar[Src[p]] do inc(p);
|
|
if p>=SrcLen then exit;
|
|
// remove * behind identifier
|
|
if Src[p]<>'*' then exit;
|
|
writeln('TConvertFunctionTypesToPointers.Execute.CheckIdentifier removing * behind reference to ',GetIdentifier(@Src[IdentPos]));
|
|
System.Delete(Src,IdentEnd,p-IdentEnd+1);
|
|
SrcLen:=length(Src);
|
|
p:=IdentEnd;
|
|
end;
|
|
|
|
var
|
|
p: Integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
FuncTypes:=nil;
|
|
try
|
|
Src:=aText.Source;
|
|
SrcLen:=length(Src);
|
|
// Search all typedef identifier ( funcname ) (
|
|
// and insert a * in front of the funcname
|
|
p:=1;
|
|
while (p<SrcLen) do begin
|
|
if (Src[p]='t') and ((p=1) or (not IsIdentChar[Src[p-1]]))
|
|
and (CompareIdentifiers('typedef',@Src[p])=0) then begin
|
|
CheckTypeDef(p);
|
|
end else
|
|
inc(p);
|
|
end;
|
|
if FuncTypes<>nil then begin
|
|
// remove the * behind all references
|
|
p:=1;
|
|
while (p<SrcLen) do begin
|
|
if (IsIdentStartChar[Src[p]]) and ((p=1) or (not IsIdentChar[Src[p-1]]))
|
|
then begin
|
|
CheckIdentifier(p);
|
|
end else
|
|
inc(p);
|
|
end;
|
|
end;
|
|
finally
|
|
if FuncTypes<>nil then begin
|
|
FuncTypes.FreeAndClear;
|
|
FuncTypes.Free;
|
|
aText.Source:=Src;
|
|
end;
|
|
end;
|
|
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TFixForwardDefinitions }
|
|
|
|
class function TFixForwardDefinitions.ClassDescription: string;
|
|
begin
|
|
Result := h2pFixForwardDefinitionsByReordering;
|
|
end;
|
|
|
|
function TFixForwardDefinitions.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TFixForwardDefinitions.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.FixForwardDefinitions(TCodeBuffer(aText.CodeBuffer)) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TFixForwardDefinitions.Execute failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TRemoveDoubleSemicolons }
|
|
|
|
class function TRemoveDoubleSemicolons.ClassDescription: string;
|
|
begin
|
|
Result := h2pRemoveDoubleSemicolons;
|
|
end;
|
|
|
|
function TRemoveDoubleSemicolons.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Position: Integer;
|
|
Source, NewSrc: String;
|
|
AtomStart: integer;
|
|
LastAtomWasSemicolon: Boolean;
|
|
SemicolonPositions: array of integer;
|
|
SemicolonCount: Integer;
|
|
i: Integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Source:=aText.Source;
|
|
//DebugLn(['TRemoveDoubleSemicolons.Execute START ',Source]);
|
|
|
|
// find all double semicolons
|
|
Position:=1;
|
|
LastAtomWasSemicolon:=false;
|
|
Setlength(SemicolonPositions,0);
|
|
SemicolonCount:=0;
|
|
repeat
|
|
ReadRawNextPascalAtom(Source,Position,AtomStart,true);
|
|
if AtomStart>length(Source) then break;
|
|
if Source[AtomStart]=';' then begin
|
|
if LastAtomWasSemicolon then begin
|
|
if length(SemicolonPositions)<=SemicolonCount then
|
|
SetLength(SemicolonPositions,length(SemicolonPositions)*2+2);
|
|
SemicolonPositions[SemicolonCount]:=AtomStart;
|
|
inc(SemicolonCount);
|
|
end;
|
|
LastAtomWasSemicolon:=true;
|
|
end else begin
|
|
LastAtomWasSemicolon:=false;
|
|
end;
|
|
until false;
|
|
|
|
// build new source without semicolons
|
|
if SemicolonCount>0 then begin
|
|
SetLength(NewSrc,length(Source)-SemicolonCount);
|
|
AtomStart:=1;
|
|
i:=0;
|
|
while i<SemicolonCount do begin
|
|
Position:=SemicolonPositions[i];
|
|
if Position>AtomStart then
|
|
System.Move(Source[AtomStart],NewSrc[AtomStart-i],Position-AtomStart);
|
|
AtomStart:=Position+1;
|
|
inc(i);
|
|
end;
|
|
Position:=length(Source)+1;
|
|
if Position>AtomStart then
|
|
System.Move(Source[AtomStart],NewSrc[AtomStart-i],Position-AtomStart);
|
|
aText.Source:=NewSrc;
|
|
end;
|
|
|
|
// clean up
|
|
Setlength(SemicolonPositions,0);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TAddMissingPointerTypes }
|
|
|
|
class function TAddMissingPointerTypes.ClassDescription: string;
|
|
begin
|
|
Result := h2pAddMissingPointerTypesLikePPPChar;
|
|
end;
|
|
|
|
function TAddMissingPointerTypes.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
{ h2pas converts implicit pointer types like 'Identifier ***' to PPPIdentifier,
|
|
but it only adds PIdentifier = ^Identifier.
|
|
This tool adds the missing
|
|
PPIdentifier = ^PIdentifier;
|
|
PPPIdentifier = ^PPIdentifier;
|
|
}
|
|
var
|
|
Tool: TCodeTool;
|
|
Definitions: TAVLTree;// tree of TCodeTreeNodeExtension
|
|
NeededPointerTypes: TAVLTree; // tree of TImplicitType
|
|
DefaultTypeSectionPos: integer;
|
|
|
|
function IdentifierIsDefined(Identifier: PChar): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if WordIsKeyWord.DoItCaseInsensitive(Identifier) then exit(true);
|
|
if WordIsPredefinedFPCIdentifier.DoItCaseInsensitive(Identifier) then exit(true);
|
|
if (Definitions<>nil)
|
|
and (Definitions.FindKey(Identifier,@CompareIdentifierWithCodeTreeNodeExt)<>nil)
|
|
then exit(true);
|
|
for i:=Low(PreDefinedH2PasTypes) to High(PreDefinedH2PasTypes) do begin
|
|
if CompareIdentifiers(Identifier,PChar(PreDefinedH2PasTypes[i]))=0 then
|
|
exit(true);
|
|
// check for predefined pointer types
|
|
if (Identifier^ in ['p','P'])
|
|
and (IsIdentChar[Identifier[1]])
|
|
and (CompareIdentifiers(@Identifier[1],PChar(PreDefinedH2PasTypes[i]))=0)
|
|
then
|
|
exit(true);
|
|
end;
|
|
//DebugLn(['IdentifierIsDefined not found: ',GetIdentifier(Identifier)]);
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure AddNeededPointerType(Position, Count: integer);
|
|
var
|
|
Item: TImplicitType;
|
|
Identifier: PChar;
|
|
AVLNode: TAVLTreeNode;
|
|
begin
|
|
if NeededPointerTypes=nil then
|
|
NeededPointerTypes:=TAVLTree.Create(@CompareImplicitTypeNames);
|
|
Identifier:=@Tool.Src[Position+Count];
|
|
AVLNode:=NeededPointerTypes.FindKey(Identifier,
|
|
@CompareImplicitTypeStringAndName);
|
|
DebugLn(['AddNeededPointerType Identifier ',GetIdentifier(Identifier),' Position=',Position,' Count=',Count]);
|
|
DebugLn(['AddNeededPointerType Position ',copy(Tool.Src,Position,100)]);
|
|
if AVLNode<>nil then begin
|
|
Item:=TImplicitType(AVLNode.Data);
|
|
if Item.MaxPosition<Count then
|
|
Item.MaxPosition:=Count;
|
|
end else begin
|
|
Item:=TImplicitType.Create;
|
|
Item.Name:=GetIdentifier(Identifier);
|
|
Item.MinPosition:=Position;
|
|
Item.MaxPosition:=Count;
|
|
NeededPointerTypes.Add(Item);
|
|
end;
|
|
end;
|
|
|
|
procedure CheckIdentifier(Position: integer);
|
|
var
|
|
Identifier: PChar;
|
|
Level: Integer;
|
|
begin
|
|
Identifier:=@Tool.Src[Position];
|
|
Level:=0;
|
|
while (Identifier[Level] in ['p','P']) do begin
|
|
// this identifier starts with a P, so it can be a pointer type
|
|
if IdentifierIsDefined(@Tool.Src[Position+Level]) then break;
|
|
inc(Level);
|
|
end;
|
|
//DebugLn(['CheckIdentifier ',GetIdentifier(Identifier),' Level=',Level]);
|
|
if Level=0 then begin
|
|
// the identifier is defined
|
|
exit;
|
|
end;
|
|
if (not (Identifier[Level] in ['p','P']))
|
|
and (IsIdentChar[Identifier[Level]])
|
|
and not (IdentifierIsDefined(@Identifier[Level])) then begin
|
|
// the base type is not defined
|
|
// => this is not a pointer type
|
|
exit;
|
|
end;
|
|
AddNeededPointerType(Position,Level);
|
|
end;
|
|
|
|
function AddNeededPointerTypesToSource(Item: TImplicitType): boolean;
|
|
var
|
|
AVLNode: TAVLTreeNode;
|
|
NodeExt: TCodeTreeNodeExtension;
|
|
Node: TCodeTreeNode;
|
|
i: Integer;
|
|
NewTxt: String;
|
|
InsertPos: LongInt;
|
|
Indent: LongInt;
|
|
Identifier: String;
|
|
begin
|
|
Result:=false;
|
|
|
|
CodeToolBoss.SourceChangeCache.MainScanner:=Tool.Scanner;
|
|
|
|
// find definition
|
|
InsertPos:=0;
|
|
if (Definitions<>nil) then begin
|
|
AVLNode:=Definitions.FindKey(Pointer(Item.Name),
|
|
@CompareIdentifierWithCodeTreeNodeExt);
|
|
if AVLNode<>nil then begin
|
|
NodeExt:=TCodeTreeNodeExtension(AVLNode.Data);
|
|
Node:=NodeExt.Node;
|
|
InsertPos:=Tool.FindLineEndOrCodeAfterPosition(Node.EndPos);
|
|
Indent:=GetLineIndent(Tool.Src,Node.StartPos);
|
|
end;
|
|
end;
|
|
if (InsertPos<1) then begin
|
|
if DefaultTypeSectionPos<1 then begin
|
|
// start a type section at the beginning
|
|
Node:=Tool.FindMainUsesNode(false);
|
|
if Node<>nil then begin
|
|
if Node.NextBrother<>nil then
|
|
Node:=Node.NextBrother;
|
|
end else begin
|
|
Node:=Tool.FindInterfaceNode;
|
|
if Node<>nil then begin
|
|
if Node.FirstChild<>nil then
|
|
Node:=Node.FirstChild;
|
|
end;
|
|
end;
|
|
if Node<>nil then begin
|
|
if Node.Desc=ctnUsesSection then begin
|
|
// insert behind node
|
|
DefaultTypeSectionPos:=
|
|
Tool.FindLineEndOrCodeAfterPosition(Node.EndPos);
|
|
end else if Node.Desc=ctnInterface then begin
|
|
// insert at end of node
|
|
DefaultTypeSectionPos:=Node.EndPos;
|
|
end else begin
|
|
// insert in front of node
|
|
DefaultTypeSectionPos:=
|
|
Tool.FindLineEndOrCodeInFrontOfPosition(Node.StartPos,true);
|
|
end;
|
|
end else begin
|
|
DefaultTypeSectionPos:=1;
|
|
end;
|
|
DebugLn(['AddNeededPointerTypesToSource start type section']);
|
|
if not CodeToolBoss.SourceChangeCache.Replace(gtEmptyLine,gtNewLine,
|
|
DefaultTypeSectionPos,DefaultTypeSectionPos,'type') then exit;
|
|
end;
|
|
InsertPos:=DefaultTypeSectionPos;
|
|
Indent:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.Indent;
|
|
end;
|
|
|
|
// add pointer types
|
|
Identifier:=Item.Name;
|
|
NewTxt:='';
|
|
for i:=Item.MaxPosition downto 1 do begin
|
|
if NewTxt<>'' then
|
|
NewTxt:=NewTxt+CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.LineEnd;
|
|
NewTxt:=NewTxt+GetIndentStr(Indent)+'P'+Identifier+'=^'+Identifier+';';
|
|
Identifier:='P'+Identifier;
|
|
end;
|
|
DebugLn(['AddNeededPointerTypesToSource Add pointer types: "',NewTxt,'"']);
|
|
Result:=CodeToolBoss.SourceChangeCache.Replace(gtNewLine,gtNewLine,
|
|
InsertPos,InsertPos,NewTxt);
|
|
end;
|
|
|
|
function CheckTypes: boolean;
|
|
var
|
|
Node: TCodeTreeNode;
|
|
begin
|
|
Node:=Tool.Tree.Root;
|
|
while Node<>nil do begin
|
|
if (Node.Desc in [ctnIdentifier,ctnOpenArrayType,
|
|
ctnRangedArrayType,ctnTypeType,ctnPointerType,ctnConstant])
|
|
and (Node.FirstChild=nil)
|
|
then begin
|
|
Tool.MoveCursorToCleanPos(Node.StartPos);
|
|
while Tool.CurPos.StartPos<Node.EndPos do begin
|
|
Tool.ReadNextAtom;
|
|
if Tool.CurPos.StartPos>=Node.EndPos then break;
|
|
if (Tool.CurPos.Flag=cafWord) then
|
|
CheckIdentifier(Tool.CurPos.StartPos);
|
|
end;
|
|
Node:=Node.NextSkipChilds;
|
|
end else
|
|
Node:=Node.Next;
|
|
end;
|
|
Result:=true;
|
|
end;
|
|
|
|
function AddNeededPointerTypesToSource: boolean;
|
|
var
|
|
AVLNode: TAVLTreeNode;
|
|
Item: TImplicitType;
|
|
begin
|
|
Result:=true;
|
|
if NeededPointerTypes<>nil then begin
|
|
AVLNode:=NeededPointerTypes.FindLowest;
|
|
while AVLNode<>nil do begin
|
|
Item:=TImplicitType(AVLNode.Data);
|
|
if not AddNeededPointerTypesToSource(Item) then exit;
|
|
AVLNode:=NeededPointerTypes.FindSuccessor(AVLNode);
|
|
end;
|
|
Result:=CodeToolBoss.SourceChangeCache.Apply;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
DebugLn(['TAddMissingPointerTypes.Execute START ',aText.Source]);
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TAddMissingPointerTypes.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
if not CodeToolBoss.Explore(TCodeBuffer(aText.CodeBuffer),Tool,true,false)
|
|
then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TAddMissingPointerTypes.Execute Explore failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
DebugLn(['TAddMissingPointerTypes.Execute ']);
|
|
Definitions:=nil;
|
|
NeededPointerTypes:=nil;
|
|
DefaultTypeSectionPos:=0;
|
|
try
|
|
// collect definitions
|
|
if not Tool.GatherUnitDefinitions(Definitions,true,false) then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TAddMissingPointerTypes.Execute GatherUnitDefinitions failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
// check all used identifiers
|
|
if not CheckTypes then exit;
|
|
// add all needed pointer types
|
|
if not AddNeededPointerTypesToSource then exit;
|
|
finally
|
|
if Definitions<>nil then begin
|
|
DisposeAVLTree(Definitions);
|
|
Definitions:=nil;
|
|
end;
|
|
if NeededPointerTypes<>nil then begin
|
|
NeededPointerTypes.FreeAndClear;
|
|
NeededPointerTypes.Free;
|
|
end;
|
|
end;
|
|
DebugLn(['TAddMissingPointerTypes.Execute END ',aText.Source]);
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TConvertEnumsToTypeDef }
|
|
|
|
class function TConvertEnumsToTypeDef.ClassDescription: string;
|
|
begin
|
|
Result := h2pGiveAnonymousCEnumsATypedefName;
|
|
end;
|
|
|
|
function TConvertEnumsToTypeDef.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Src: String;
|
|
SrcLen: Integer;
|
|
|
|
function CreateEnumName(StartPos, EndPos: integer): string;
|
|
var
|
|
AtomStart: LongInt;
|
|
begin
|
|
Result:='';
|
|
AtomStart:=StartPos;
|
|
while StartPos<=EndPos do begin
|
|
ReadNextCAtom(Src,StartPos,AtomStart);
|
|
if AtomStart>SrcLen then exit;
|
|
if IsIdentStartChar[Src[AtomStart]] then begin
|
|
Result:=Result+copy(Src,AtomStart,StartPos-AtomStart);
|
|
if length(Result)>60 then exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
p: Integer;
|
|
AtomStart: Integer;
|
|
LastAtomStart: LongInt;
|
|
Changed: Boolean;
|
|
|
|
procedure AdjustAfterReplace(var APosition: integer;
|
|
FromPos, ToPos, NewLength: integer);
|
|
begin
|
|
if APosition<FromPos then
|
|
exit
|
|
else if APosition<ToPos then
|
|
APosition:=FromPos
|
|
else
|
|
inc(APosition,NewLength-(FromPos-ToPos));
|
|
end;
|
|
|
|
procedure Replace(FromPos, ToPos: integer; const NewSrc: string);
|
|
begin
|
|
DebugLn(['TConvertEnumsToTypeDef.Execute.Replace ',FromPos,'-',ToPos,' NewSrc="',NewSrc,'"']);
|
|
Src:=copy(Src,1,FromPos-1)+NewSrc+copy(Src,ToPos,length(Src));
|
|
AdjustAfterReplace(p,FromPos,ToPos,length(NewSrc));
|
|
AdjustAfterReplace(AtomStart,FromPos,ToPos,length(NewSrc));
|
|
AdjustAfterReplace(LastAtomStart,FromPos,ToPos,length(NewSrc));
|
|
Changed:=true;
|
|
end;
|
|
|
|
var
|
|
EnumStart: LongInt;
|
|
EnumEnd: LongInt;
|
|
EnumName: String;
|
|
BracketStart: LongInt;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Changed:=false;
|
|
Src:=aText.Source;
|
|
SrcLen:=length(Src);
|
|
p:=1;
|
|
AtomStart:=1;
|
|
LastAtomStart:=-1;
|
|
repeat
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if p>SrcLen then break;
|
|
//DebugLn(['TConvertEnumsToTypeDef.Execute ',AtomStart,' "',dbgstr(copy(Src,AtomStart,p-AtomStart)),'"']);
|
|
case Src[AtomStart] of
|
|
'a'..'z','A'..'Z','_':
|
|
begin
|
|
// identifier
|
|
if (CompareCIdentifiers(@Src[AtomStart],'enum')=0)
|
|
and ((LastAtomStart<1)
|
|
or (CompareCIdentifiers(@Src[AtomStart],'typedef')<>0)) then
|
|
begin
|
|
// enum without typedef
|
|
DebugLn(['TConvertEnumsToTypeDef.Execute enum without typedef found']);
|
|
EnumStart:=AtomStart;
|
|
// read curly bracket open
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if (AtomStart>SrcLen) or (Src[AtomStart]<>'{') then break;
|
|
BracketStart:=AtomStart;
|
|
// read til curly bracket close
|
|
if not ReadTilCBracketClose(Src,AtomStart) then break;
|
|
p:=AtomStart;
|
|
// read semicolon
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if (AtomStart>SrcLen) or (Src[AtomStart]<>';') then break;
|
|
EnumEnd:=AtomStart;
|
|
DebugLn(['TConvertEnumsToTypeDef.Execute Enum block: ',copy(Src,EnumStart,EnumEnd-EnumStart)]);
|
|
// read enums to create a unique name
|
|
EnumName:=CreateEnumName(BracketStart,EnumEnd);
|
|
if EnumName='' then begin
|
|
// empty enum => remove
|
|
Replace(EnumStart,EnumEnd,'');
|
|
end else begin
|
|
// insert 'typedef' and name
|
|
// IMPORTANT: insert in reverse order
|
|
Replace(EnumEnd,EnumEnd,EnumName);
|
|
Replace(EnumStart,EnumStart,'typedef ');
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
LastAtomStart:=AtomStart;
|
|
until false;
|
|
|
|
if Changed then
|
|
aText.Source:=Src;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TCommentComplexCMacros }
|
|
|
|
class function TCommentComplexCMacros.ClassDescription: string;
|
|
begin
|
|
Result := h2pCommentMacrosThatAreTooComplexForH2pas;
|
|
end;
|
|
|
|
function TCommentComplexCMacros.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Src: String;
|
|
SrcLen: Integer;
|
|
|
|
function DefineIsTooComplex(StartPos, EndPos: integer): boolean;
|
|
// h2pas has problems with
|
|
// - backslash + newline
|
|
// - whole functions { }
|
|
var
|
|
p: LongInt;
|
|
AtomStart: integer;
|
|
begin
|
|
p:=StartPos;
|
|
repeat
|
|
ReadRawNextCAtom(Src,p,AtomStart);
|
|
if (AtomStart>=EndPos) or (AtomStart>length(Src)) then break;
|
|
if Src[AtomStart]='{' then begin
|
|
// this macro is a whole function => too complex
|
|
exit(true);
|
|
end;
|
|
if (Src[AtomStart] in [#10,#13]) then begin
|
|
// this macro uses multiple lines => too complex
|
|
exit(true);
|
|
end;
|
|
until false;
|
|
Result:=false;
|
|
end;
|
|
|
|
var
|
|
Changed: Boolean;
|
|
p: Integer;
|
|
AtomStart: Integer;
|
|
|
|
procedure AdjustAfterReplace(var APosition: integer;
|
|
FromPos, ToPos, NewLength: integer);
|
|
begin
|
|
if APosition<FromPos then
|
|
exit
|
|
else if APosition<ToPos then
|
|
APosition:=FromPos
|
|
else
|
|
inc(APosition,NewLength-(FromPos-ToPos));
|
|
end;
|
|
|
|
procedure Replace(FromPos, ToPos: integer; const NewSrc: string);
|
|
begin
|
|
//DebugLn(['TCommentComplexCMacros.Execute.Replace ',FromPos,'-',ToPos,' NewSrc="',NewSrc,'"']);
|
|
Src:=copy(Src,1,FromPos-1)+NewSrc+copy(Src,ToPos,length(Src));
|
|
AdjustAfterReplace(p,FromPos,ToPos,length(NewSrc));
|
|
AdjustAfterReplace(AtomStart,FromPos,ToPos,length(NewSrc));
|
|
Changed:=true;
|
|
end;
|
|
|
|
procedure Comment(StartPos, EndPos: integer);
|
|
begin
|
|
// replace sub comments
|
|
while (StartPos<EndPos-1) do begin
|
|
if (Src[StartPos]='/') and (Src[StartPos+1]='*') then begin
|
|
// sub comment found -> disable
|
|
// IMPORTANT: replacement must be the same size to keep the positions
|
|
Replace(StartPos,StartPos+1,'(');
|
|
end;
|
|
if (Src[StartPos]='*') and (Src[StartPos+1]='/') then begin
|
|
// sub comment found -> disable
|
|
// IMPORTANT: replacement must be the same size to keep the positions
|
|
Replace(StartPos+1,StartPos+2,')');
|
|
end;
|
|
inc(StartPos);
|
|
end;
|
|
|
|
// IMPORTANT: insert in reverse order
|
|
Replace(EndPos,EndPos,'*/');
|
|
Replace(StartPos,StartPos,'/*');
|
|
end;
|
|
|
|
var
|
|
DefineStart: LongInt;
|
|
DefineEnd: LongInt;
|
|
ValueStart: LongInt;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Changed:=false;
|
|
Src:=aText.Source;
|
|
SrcLen:=length(Src);
|
|
p:=1;
|
|
AtomStart:=1;
|
|
repeat
|
|
ReadRawNextCAtom(Src,p,AtomStart);
|
|
if p>SrcLen then break;
|
|
if (Src[AtomStart]='#') and (AtomStart<SrcLen) then begin
|
|
// pragma found
|
|
if CompareCIdentifiers(@Src[AtomStart+1],'define')=0 then begin
|
|
// #define found
|
|
DefineStart:=AtomStart;
|
|
inc(p,length('define'));
|
|
ValueStart:=p;
|
|
ReadTilCLineEnd(Src,p);
|
|
DefineEnd:=p;
|
|
if DefineIsTooComplex(ValueStart,DefineEnd) then begin
|
|
DebugLn(['TCommentComplexCMacros.Execute commenting macro "',dbgstr(copy(Src,DefineStart,DefineEnd-DefineStart)),'"']);
|
|
Comment(DefineStart,DefineEnd);
|
|
end;
|
|
end;
|
|
end;
|
|
until false;
|
|
|
|
if Changed then
|
|
aText.Source:=Src;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TCommentComplexCFunctions }
|
|
|
|
class function TCommentComplexCFunctions.ClassDescription: string;
|
|
begin
|
|
Result := h2pCommentFunctionsThatAreTooComplexForH2pas;
|
|
end;
|
|
|
|
function TCommentComplexCFunctions.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Src: String;
|
|
SrcLen: Integer;
|
|
|
|
function DefineIsTooComplex(StartPos, EndPos: integer): boolean;
|
|
// h2pas has problems with
|
|
// - backslash + newline
|
|
// - whole functions { }
|
|
begin
|
|
while (StartPos<EndPos) do begin
|
|
if Src[StartPos]='{' then begin
|
|
// this macro is a whole function => too complex
|
|
exit(true);
|
|
end;
|
|
if (Src[StartPos] in [#10,#13]) then begin
|
|
// this macro uses multiple lines => too complex
|
|
exit(true);
|
|
end;
|
|
inc(StartPos);
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
var
|
|
Changed: Boolean;
|
|
p: Integer;
|
|
AtomStart: Integer;
|
|
DefinitionStart: Integer;
|
|
|
|
procedure AdjustAfterReplace(var APosition: integer;
|
|
FromPos, ToPos, NewLength: integer);
|
|
begin
|
|
if APosition<FromPos then
|
|
exit
|
|
else if APosition<ToPos then
|
|
APosition:=FromPos
|
|
else
|
|
inc(APosition,NewLength-(FromPos-ToPos));
|
|
end;
|
|
|
|
procedure Replace(FromPos, ToPos: integer; const NewSrc: string);
|
|
begin
|
|
Src:=copy(Src,1,FromPos-1)+NewSrc+copy(Src,ToPos,length(Src));
|
|
AdjustAfterReplace(p,FromPos,ToPos,length(NewSrc));
|
|
AdjustAfterReplace(AtomStart,FromPos,ToPos,length(NewSrc));
|
|
AdjustAfterReplace(DefinitionStart,FromPos,ToPos,length(NewSrc));
|
|
Changed:=true;
|
|
end;
|
|
|
|
procedure Comment(StartPos, EndPos: integer);
|
|
begin
|
|
// replace sub comments
|
|
while (StartPos<EndPos-1) do begin
|
|
if (Src[StartPos]='/') and (Src[StartPos+1]='*') then begin
|
|
// sub comment found -> disable
|
|
// IMPORTANT: replacement must be the same size to keep the positions
|
|
Replace(StartPos,StartPos+1,'(');
|
|
end;
|
|
if (Src[StartPos]='*') and (Src[StartPos+1]='/') then begin
|
|
// sub comment found -> disable
|
|
// IMPORTANT: replacement must be the same size to keep the positions
|
|
Replace(StartPos+1,StartPos+2,')');
|
|
end;
|
|
inc(StartPos);
|
|
end;
|
|
|
|
// IMPORTANT: insert in reverse order
|
|
Replace(EndPos,EndPos,'*/');
|
|
Replace(StartPos,StartPos,'/*');
|
|
end;
|
|
|
|
function ReadFunction: boolean;
|
|
var
|
|
FuncEnd: LongInt;
|
|
begin
|
|
Result:=false;
|
|
//DebugLn(['ReadFunction START "',copy(Src,AtomStart,p-AtomStart),'"']);
|
|
// a C function works like this:
|
|
// [modifiers, macros] type name(param list){ statements }
|
|
// 'type' can be an identifier or identifier* or something with brackets
|
|
|
|
// read name
|
|
if not IsIdentStartChar[Src[AtomStart]] then exit;
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if p>SrcLen then exit;
|
|
// read round bracket open
|
|
if Src[AtomStart]<>'(' then exit;
|
|
p:=AtomStart;
|
|
if not ReadTilCBracketClose(Src,p) then exit;
|
|
// read curly bracket open
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if p>SrcLen then exit;
|
|
if Src[AtomStart]<>'{' then exit;
|
|
p:=AtomStart;
|
|
if not ReadTilCBracketClose(Src,p) then exit;
|
|
// function found
|
|
FuncEnd:=p;
|
|
Result:=true;
|
|
DebugLn(['TCommentComplexCFunctions.Execute.ReadFunction Function="',copy(Src,DefinitionStart,FuncEnd-DefinitionStart),'"']);
|
|
Comment(DefinitionStart,FuncEnd);
|
|
end;
|
|
|
|
var
|
|
OldP: LongInt;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Changed:=false;
|
|
Src:=aText.Source;
|
|
SrcLen:=length(Src);
|
|
p:=1;
|
|
AtomStart:=1;
|
|
DefinitionStart:=0;
|
|
repeat
|
|
// read next definition
|
|
ReadNextCAtom(Src,p,AtomStart);
|
|
if p>SrcLen then break;
|
|
if Src[AtomStart]=';' then begin
|
|
// definition end found
|
|
DefinitionStart:=0;
|
|
continue;
|
|
end else if Src[AtomStart]='{' then begin
|
|
// block found = definition end found
|
|
DefinitionStart:=0;
|
|
p:=AtomStart;
|
|
if not ReadTilCBracketClose(Src,p) then break;
|
|
continue;
|
|
end else begin
|
|
// in definition
|
|
if DefinitionStart<1 then
|
|
DefinitionStart:=AtomStart;
|
|
if Src[AtomStart] in ['(','['] then begin
|
|
// skip bracket
|
|
p:=AtomStart;
|
|
if not ReadTilCBracketClose(Src,p) then break;
|
|
end else if IsIdentStartChar[Src[AtomStart]] then begin
|
|
// identifier found => check if function
|
|
OldP:=p;
|
|
if ReadFunction then begin
|
|
DefinitionStart:=0;
|
|
end else begin
|
|
p:=OldP;
|
|
end;
|
|
end;
|
|
end;
|
|
until false;
|
|
|
|
if Changed then
|
|
aText.Source:=Src;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TAddToUsesSection }
|
|
|
|
procedure TAddToUsesSection.SetUseUnits(const AValue: TStrings);
|
|
begin
|
|
if FUseUnits=AValue then exit;
|
|
FUseUnits.Assign(AValue);
|
|
end;
|
|
|
|
constructor TAddToUsesSection.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FUseUnits:=TStringList.Create;
|
|
end;
|
|
|
|
destructor TAddToUsesSection.Destroy;
|
|
begin
|
|
FreeAndNil(FUseUnits);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TAddToUsesSection.ClassDescription: string;
|
|
begin
|
|
Result := h2pAddUnitsToUsesSection;
|
|
end;
|
|
|
|
function TAddToUsesSection.Execute(aText: TIDETextConverter): TModalResult;
|
|
var
|
|
AUnitName: string;
|
|
i: Integer;
|
|
begin
|
|
Result:=mrCancel;
|
|
if (not FilenameIsPascalUnit(aText.Filename)) then begin
|
|
DebugLn(['TAddToUsesSection.Execute file is not pascal: ',aText.Filename]);
|
|
exit(mrOk);// ignore
|
|
end;
|
|
for i:=0 to FUseUnits.Count-1 do begin
|
|
AUnitName:=FUseUnits[i];
|
|
if (AUnitName='') then continue;
|
|
if not IsValidIdent(AUnitName) then
|
|
raise Exception.Create(Format(h2pTAddToUsesSectionExecuteInvalidUnitname, [AUnitName]));
|
|
if not CodeToolBoss.AddUnitToMainUsesSection(TCodeBuffer(aText.CodeBuffer),AUnitName,'')
|
|
then begin
|
|
AssignCodeToolBossError;
|
|
DebugLn(['TAddToUsesSection.Execute failed ',CodeToolBoss.ErrorMessage]);
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
{ TAddMissingMacroBrackets }
|
|
|
|
class function TAddMissingMacroBrackets.ClassDescription: string;
|
|
begin
|
|
Result := h2pAddMissingBracketsAroundMacroValues;
|
|
end;
|
|
|
|
function TAddMissingMacroBrackets.Execute(aText: TIDETextConverter
|
|
): TModalResult;
|
|
var
|
|
Macro: String;
|
|
Lines: TStrings;
|
|
i: Integer;
|
|
Line: string;
|
|
Value: String;
|
|
begin
|
|
Result:=mrCancel;
|
|
if aText=nil then exit;
|
|
Lines:=aText.Strings;
|
|
i:=0;
|
|
while i<=Lines.Count-1 do begin
|
|
Line:=Lines[i];
|
|
// example: #define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
|
|
if REMatches(Line,'^(#define\s+[a-zA-Z0-9_]+\s+)(.+)')
|
|
then begin
|
|
Macro:=REVar(1);
|
|
Value:=REVar(2);
|
|
if (Value<>'') and (Value[1]<>'(')
|
|
and (REMatches(Value,'[^a-zA-Z0-9_()]')) then begin
|
|
// macro needs values
|
|
Line:=Macro+'('+Value+')';
|
|
Lines[i]:=Line;
|
|
end;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result:=mrOk;
|
|
end;
|
|
|
|
end.
|