Componentes.Terceros.RemObj.../internal/5.0.23.613/1/RemObjects SDK for Delphi/Source/CodeGen2/uRODLSplitableConverter.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10
- Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
2007-09-10 14:06:19 +00:00

570 lines
18 KiB
ObjectPascal

unit uRODLSplitableConverter;
{----------------------------------------------------------------------------}
{ RemObjects SDK Library - CodeGen2 }
{ }
{ compiler: Delphi 5 and up, Kylix 2 and up }
{ platform: Win32, Linux }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the RemObjects SDK }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$IFDEF LINUX}
{$I ../RemObjects.inc}
{$ELSE}
{$I ..\RemObjects.inc}
{$ENDIF LINUX}
interface
uses
Classes, IniFiles, Contnrs, uRODL, uROClasses, uRODLLineStream, uRODLTemplateBasedConverter;
type
TRODLSplitableConverterFileList = class;
TRODLSplitableConverter = class (TRODLTemplateBasedConverter)
private
FTargetEntities: TStringList;
FOutputDir: string;
protected
FWrapperTemplateName: string;
FSplit: Boolean;
FFiles: TRODLSplitableConverterFileList;
procedure ProcessTemplate(const aLibrary: TRODLLibrary; template: TLineStream); override;
procedure SetupFiles(const aLibrary: TRODLLibrary); virtual; abstract;
procedure WriteWrapper(TypesList: TStringList; UsesList: TStringList); virtual;
function GetSplitFilesSuffix: string; virtual; abstract;
procedure AddEntityTypes(Types: {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF}; const AEntity: TRODLEntity; const unitName: string); virtual;
procedure ResolveRequiredUnits;
public
constructor Create(const aLibrary: TRODLLibrary; const aTemplateFileName: string; const aUnitName: string;
const ASplit: Boolean = False; const AOutputDir: string = '';
const AWrapperTemplateName: string = ''; const aTargetEntities: string = ''); reintroduce; virtual;
destructor Destroy; override;
property Split: Boolean read FSplit;
property SplitFilesSuffix: string read GetSplitFilesSuffix;
property OutputDir: string read FOutputDir;
end;
TRODLSplitableConverterFile = class
private
FEnums: TObjectList;
FArrays: TObjectList;
FStructs: TObjectList;
FEventSinks: TObjectList;
FExceptions: TObjectList;
FUnitName: string;
FServices: TObjectList;
FLibrary: TRODLLibrary;
FActiveList: TObjectList;
FLibraryList: IROStrings;
FConverter: TRODLSplitableConverter;
FRequiredUnits: TStringList;
function GetServices: TObjectList;
function GetUnitName: string;
function GetExceptions: TObjectList;
function GetEventSinks: TObjectList;
function GetStructs: TObjectList;
function GetArrays: TObjectList;
function GetEnums: TObjectList;
procedure SetupLists;
public
constructor Create(const aLibrary: TRODLLibrary; const aConverter: TRODLSplitableConverter);
destructor Destroy; override;
function GetActiveList: TObjectList;
function GetLibraryList: IROStrings;
property Services: TObjectList read GetServices;
property Enums: TObjectList read GetEnums;
property Arrays: TObjectList read GetArrays;
property Structs: TObjectList read GetStructs;
property EventSinks: TObjectList read GetEventSinks;
property Exceptions: TObjectList read GetExceptions;
property UnitName: string read GetUnitName write FUnitName;
property RequiredUnits: TStringList read FRequiredUnits write FRequiredUnits;
end;
TRODLSplitableConverterFileList = class (TObjectList)
private
function GetItem(Index: Integer): TRODLSplitableConverterFile;
procedure SetItem(Index: Integer; const Value: TRODLSplitableConverterFile);
public
property Items[Index: Integer]: TRODLSplitableConverterFile read GetItem write SetItem; default;
end;
implementation
uses
SysUtils, uRODLTemplateBasedConverterUtils;
{ TRODLSplitableConverter }
procedure TRODLSplitableConverter.AddEntityTypes(Types: {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF};
const AEntity: TRODLEntity; const unitName: string);
begin
Types.Values[AEntity.Name] := unitName;
end;
constructor TRODLSplitableConverter.Create(const aLibrary: TRODLLibrary;
const aTemplateFileName, aUnitName: string; const ASplit: Boolean;
const AOutputDir, AWrapperTemplateName, aTargetEntities: string);
begin
// Call inherited with nil so that convert is not called, allowing us
// to setup the optional sections. Setting up the optional sections before
// calling the inherited Create is not an option, the section list would
// not have been created
inherited Create(nil, aTemplateFileName, aUnitName, '');
FSplit := ASplit;
FFiles := TRODLSplitableConverterFileList.Create(True);
FOutputDir := AOutputDir;
if Length(FOutputDir) = 0 then
FOutputDir := '.';
FWrapperTemplateName := AWrapperTemplateName;
FTargetEntities := TStringList.Create;
FTargetEntities.Sorted := True;
FTargetEntities.Delimiter := ',';
FTargetEntities.DelimitedText := aTargetEntities;
// Setup the optional sections
// Now that everything is done, call convert if need be.
if (aLibrary <> nil) then Convert(aLibrary);
end;
destructor TRODLSplitableConverter.Destroy;
begin
FTargetEntities.Free;
FFiles.Free;
inherited Destroy;
end;
procedure TRODLSplitableConverter.ProcessTemplate(const aLibrary: TRODLLibrary;
template: TLineStream);
var
I: Integer;
curFile: TRODLSplitableConverterFile;
J: Integer;
UsesList: TStringList;
TypesList: {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF};
curEntity: TRODLEntity;
originalUnitName: string;
originalRequiredUnits: string;
oneEntitySelected: Boolean;
begin
if Split then
begin
SetupFiles(aLibrary);
ResolveRequiredUnits;
UsesList := TStringList.Create;
TypesList := {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF}.Create;
originalUnitName := UnitName;
originalRequiredUnits := RequiredUnits;
try
for I := 0 to FFiles.Count - 1 do
begin
curFile := FFiles[I];
UsesList.Add(curFile.UnitName);
FOrderedServices.Clear;
FOrderedArrays.Clear;
FOrderedStructs.Clear;
FOrderedEnums.Clear;
FOrderedExceptions.Clear;
FOrderedEventSinks.Clear;
oneEntitySelected := False;
for J := 0 to curFile.GetActiveList.Count - 1 do
begin
curEntity := curFile.GetActiveList[J] as TRODLEntity;
curFile.GetLibraryList.AddObject(curEntity.Name, curEntity);
AddEntityTypes(TypesList, curEntity, curFile.UnitName);
oneEntitySelected := oneEntitySelected or (FTargetEntities.IndexOf(curEntity.Name) > -1);
end;
// Only generate if no entities were indicated or if at least one
// of the entities in the current file was found earlier in the list.
if (FTargetEntities.Count = 0) or oneEntitySelected then
begin
Buffer.Clear;
template.Position := 0;
UnitName := curFile.UnitName;
RequiredUnits := originalRequiredUnits;
if curFile.RequiredUnits.Count > 0 then
begin
if Length(RequiredUnits) > 0 then
RequiredUnits := RequiredUnits + ',';
RequiredUnits := RequiredUnits + curFile.RequiredUnits.DelimitedText;
end;
inherited ProcessTemplate(aLibrary, template);
Buffer.SaveToFile(StrEnsureSuffix('\', OutputDir)+ curFile.UnitName + FileExtension);
end;
end;
UnitName := originalUnitName;
RequiredUnits := originalRequiredUnits;
WriteWrapper(TypesList, UsesList);
finally
UsesList.Free;
TypesList.Free;
end;
end
else
begin
inherited ProcessTemplate(aLibrary, template);
end;
end;
procedure TRODLSplitableConverter.ResolveRequiredUnits;
var
curFileIndex: Integer;
curFile: TRODLSplitableConverterFile;
curEntityIndex: Integer;
curEntity: TRODLEntity;
curService: TRODLBaseService;
curArray: TRODLArray;
curStruct: TRODLBaseStruct;
typesCache: {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF};
curFieldIndex: Integer;
curOpIndex: Integer;
curOp: TRODLOperation;
curParamIndex: Integer;
notFounds: TStringList;
procedure AddRequiredUnits(const typeName: string);
var
resultIndex: Integer;
begin
resultIndex := notFounds.IndexOf(typeName);
if resultIndex = -1 then
begin
unitName := typesCache.Values[typeName];
if Length(unitName) > 0 then
begin
if unitName <> curFile.UnitName then
curFile.RequiredUnits.Add(unitName);
end
else
begin
notFounds.Add(typeName);
end;
end;
end;
begin
// In order to find out if a splitted file requires other files, we need
// to know which types are where. So we fill in the typesCache list with
// Name/Value pairs, where the name is the type and the value the unit
// where it is located.
// Once this is done, we go look at all the types in all the files, and
// we look for them in the cache. If the type is found, then the unit it
// resides in is added to the list of required units. If it is not found
// it is added to the notFounds list. This second list allows to speed
// the process a lot because looking through the typesCache list is slow
// and many regular types (Integer, String...) are used a lot but there are
// not many of them. Hence the second list allows to know very fast for these
// that they were not found in any unit.
typesCache := {$IFDEF FPC}TStringList{$ELSE}THashedStringList{$ENDIF}.Create;
notFounds := TStringList.Create;
try
notFounds.Sorted := True;
for curFileIndex := 0 to FFiles.Count - 1 do
begin
curFile := FFiles[curFileIndex];
for curEntityIndex := 0 to curFile.GetActiveList.Count - 1 do
begin
curEntity := curFile.GetActiveList[curEntityIndex] as TRODLEntity;
typesCache.Values[curEntity.Name] := curFile.UnitName;
end;
end;
for curFileIndex := 0 to FFiles.Count - 1 do
begin
curFile := FFiles[curFileIndex];
curFile.RequiredUnits.Clear;
for curEntityIndex := 0 to curFile.GetActiveList.Count - 1 do
begin
curEntity := curFile.GetActiveList[curEntityIndex] as TRODLEntity;
if curEntity is TRODLBaseService then
begin
curService := curEntity as TRODLBaseService;
AddRequiredUnits(curService.Ancestor);
for curOpIndex := 0 to curService.Default.Count - 1 do
begin
curOp := curService.Default.Items[curOpIndex];
if Assigned(curOp.Result) then
AddRequiredUnits(curOp.Result.DataType);
for curParamIndex := 0 to curOp.Count - 1 do
AddRequiredUnits(curOp.Items[curParamIndex].DataType);
end;
end
else
if curEntity is TRODLArray then
begin
curArray := curEntity as TRODLArray;
AddRequiredUnits(curArray.ElementType);
end
else
if curEntity is TRODLBaseStruct then
begin
curStruct := curEntity as TRODLBaseStruct;
AddRequiredUnits(curStruct.Ancestor);
for curFieldIndex := 0 to curStruct.Count - 1 do
AddRequiredUnits(curStruct.Items[curFieldIndex].DataType);
end;
end;
curFile.RequiredUnits.Delimiter := ',';
end;
finally
notFounds.Free;
typesCache.Free;
end;
end;
procedure TRODLSplitableConverter.WriteWrapper(TypesList,
UsesList: TStringList);
var
template: TLineStream;
content: TStringList;
curLine: string;
sectionContent: string;
I: Integer;
typeUnitName: string;
begin
template := TLineStream.Create('');
try
content := TStringList.Create;
try
if FileExists(FWrapperTemplateName) then
content.LoadFromFile(FWrapperTemplateName)
else
LoadTemplateFromResource(content, FWrapperTemplateName);
template.WriteString(content.Text);
template.Position := 0;
finally
content.Free;
end;
Buffer.Clear;
while not template.Eof do
begin
curLine := template.ReadLine;
MacroReplace(curLine, '%',
['UNIT_NAME', FLibrary.Name + SplitFilesSuffix
]);
if SectionStart(curLine, 'USES') then
begin
sectionContent := FinishSection('USES', template);
for I := 0 to UsesList.Count - 1 do
begin
curLine := sectionContent;
MacroReplace(curLine, '%',
['USED_UNIT_NAME', UsesList[I]
]);
if I = UsesList.Count-1 then
curLine := StrEnsureNoSuffix(',', curLine);
Write(curLine);
end;
end
else
if SectionStart(curLine, 'TYPES') then
begin
sectionContent := FinishSection('TYPES', template);
for I := 0 to TypesList.Count - 1 do
begin
curLine := sectionContent;
typeUnitName := TypesList[I];
typeUnitName := Copy(typeUnitName, Pos('=', typeUnitName)+1, MAXINT);
MacroReplace(curLine, '%',
['TYPE_UNIT_NAME', typeUnitName,
'TYPE_NAME', TypesList.Names[I]
]);
Write(curLine);
end;
end
else
begin
Write(curLine);
end;
end;
finally
template.Free;
end;
end;
{ TRODLIntfConverterFileList }
function TRODLSplitableConverterFileList.GetItem(
Index: Integer): TRODLSplitableConverterFile;
begin
Result := inherited Items[Index] as TRODLSplitableConverterFile;
end;
procedure TRODLSplitableConverterFileList.SetItem(Index: Integer;
const Value: TRODLSplitableConverterFile);
begin
inherited Items[Index] := Value;
end;
{ TRODLIntfConverterFile }
constructor TRODLSplitableConverterFile.Create(const aLibrary: TRODLLibrary; const aConverter: TRODLSplitableConverter);
begin
inherited Create;
FLibrary := aLibrary;
FConverter := aConverter;
FRequiredUnits := TStringList.Create;
FRequiredUnits.Sorted := True;
FRequiredUnits.Duplicates := dupIgnore;
end;
destructor TRODLSplitableConverterFile.Destroy;
begin
FRequiredUnits.Free;
FEnums.Free;
FArrays.Free;
FStructs.Free;
FEventSinks.Free;
FExceptions.Free;
FServices.Free;
inherited Destroy;
end;
function TRODLSplitableConverterFile.GetActiveList: TObjectList;
begin
if FActiveList = nil then
begin
SetupLists;
end;
Result := FActiveList;
end;
procedure TRODLSplitableConverterFile.SetupLists;
begin
if Services.Count > 0 then
begin
FActiveList := Services;
FLibraryList := FConverter.OrderedServices;
end
else if Arrays.Count > 0 then
begin
FActiveList := Arrays;
FLibraryList := FConverter.OrderedArrays;
end
else if Structs.Count > 0 then
begin
FActiveList := Structs;
FLibraryList := FConverter.OrderedStructs;
end
else if Enums.Count > 0 then
begin
FActiveList := Enums;
FLibraryList := FConverter.OrderedEnums;
end
else if EventSinks.Count > 0 then
begin
FActiveList := EventSinks;
FLibraryList := FConverter.OrderedEventSinks;
end
else if Exceptions.Count > 0 then
begin
FActiveList := Exceptions;
FLibraryList := FConverter.OrderedExceptions;
end;
end;
function TRODLSplitableConverterFile.GetArrays: TObjectList;
begin
if not Assigned(FArrays) then
FArrays := TObjectList.Create(False);
Result := FArrays;
end;
function TRODLSplitableConverterFile.GetEnums: TObjectList;
begin
if not Assigned(FEnums) then
FEnums := TObjectList.Create(False);
Result := FEnums;
end;
function TRODLSplitableConverterFile.GetEventSinks: TObjectList;
begin
if not Assigned(FEventSinks) then
FEventSinks := TObjectList.Create(False);
Result := FEventSinks;
end;
function TRODLSplitableConverterFile.GetExceptions: TObjectList;
begin
if not Assigned(FExceptions) then
FExceptions := TObjectList.Create(False);
Result := FExceptions;
end;
function TRODLSplitableConverterFile.GetLibraryList: IROStrings;
begin
if FLibraryList = nil then
begin
SetupLists;
end;
Result := FLibraryList;
end;
function TRODLSplitableConverterFile.GetServices: TObjectList;
begin
if not Assigned(FServices) then
FServices := TObjectList.Create(False);
Result := FServices;
end;
function TRODLSplitableConverterFile.GetStructs: TObjectList;
begin
if not Assigned(FStructs) then
FStructs := TObjectList.Create(False);
Result := FStructs;
end;
function TRODLSplitableConverterFile.GetUnitName: string;
var
list: TObjectList;
I: Integer;
begin
if FUnitName = '' then
begin
list := GetActiveList;
for I := 0 to list.Count - 1 do
FUnitName := FUnitName + (list[i] as TRODLEntity).Name + '_';
FUnitName := FLibrary.Name + '_' + Copy(FUnitName, 1, Length(FUnitName)-1) + FConverter.SplitFilesSuffix;
end;
Result := FUnitName;
end;
end.