{****************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License } { Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may } { obtain a copy of the License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, } { WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License } { for the specific language governing rights and limitations under the } { License. } { } { The Original Code is JclOtaTemplates.pas. } { } { The Initial Developer of the Original Code is Florent Ouchet } { } { Portions created by Florent Ouchet are Copyright (C) of Florent Ouchet. } { } { Contributors: } { } {****************************************************************************} { } { Last modified: $Date: $ } { } {****************************************************************************} unit JclOtaTemplates; interface {$I jcl.inc} uses Classes, JclBorlandTools; type TJclOtaTemplateParams = class(TPersistent) protected FLanguage: TJclBorPersonality; public function GetBoolValue(const Name: string): Boolean; virtual; function IsDefined(const Name: string): Boolean; virtual; function GetStrValue(const Name: string): string; virtual; function GetIntValue(const Name: string): Integer; virtual; function GetStringsValue(const Name: string): TStrings; virtual; property Language: TJclBorPersonality read FLanguage write FLanguage; end; const ModulePattern = '%MODULENAME%'; FormPattern = '%FORMNAME%'; AncestorPattern = '%ANCESTORNAME%'; function GetFinalFormContent(const Content, FormIdent, AncestorIdent: string): string; function GetFinalHeaderContent(const Content, ModuleIdent, FormIdent, AncestorIdent: string): string; function GetFinalSourceContent(const Content, ModuleIdent, FormIdent, AncestorIdent: string): string; function ApplyTemplate(const Template: string; const Params: TJclOtaTemplateParams): string; implementation uses SysUtils, {$IFDEF HAS_UNIT_VARIANTS} // Variants, {$ENDIF HAS_UNIT_VARIANTS} TypInfo, JclStrings, JclSysUtils; function GetFinalFormContent(const Content, FormIdent, AncestorIdent: string): string; begin Result := StringReplace(Content, FormPattern, FormIdent, [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, AncestorPattern, AncestorIdent, [rfReplaceAll, rfIgnoreCase]); end; function GetFinalHeaderContent(const Content, ModuleIdent, FormIdent, AncestorIdent: string): string; begin Result := StringReplace(Content, FormPattern, FormIdent, [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, AncestorPattern, AncestorIdent, [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, ModulePattern, ModuleIdent, [rfReplaceAll, rfIgnoreCase]); end; function GetFinalSourceContent(const Content, ModuleIdent, FormIdent, AncestorIdent: string): string; begin Result := StringReplace(Content, FormPattern, FormIdent, [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, AncestorPattern, AncestorIdent, [rfReplaceAll, rfIgnoreCase]); Result := StringReplace(Result, ModulePattern, ModuleIdent, [rfReplaceAll, rfIgnoreCase]); end; function ApplyTemplate(const Template: string; const Params: TJclOtaTemplateParams): string; procedure CopyStr(var Dest: string; var IndexDest: Integer; var DestCharCount: Integer; const Src: string; IndexSrc: Integer; CharCount: Integer); begin if (Length(Src) - IndexSrc + 1) < CharCount then CharCount := Length(Src) - IndexSrc + 1; while (DestCharCount - IndexDest + 1) < CharCount do begin DestCharCount := 2 * DestCharCount; SetLength(Dest, DestCharCount); end; if CharCount > 0 then begin Move(Src[IndexSrc], Dest[IndexDest], CharCount); Inc(IndexDest, CharCount); end; end; function SkipBlanks(const Str: string; const Index: Integer; Count: Integer): Integer; begin Result := Index; while (Result <= Count) and (Str[Result] in AnsiWhiteSpace) do Inc(Result); end; function GetIdentifier(const Str: string; var Index: Integer; Count: Integer): string; var IndexStart: Integer; begin IndexStart := Index; while (Index <= Count) and (Str[Index] in ['0'..'9', 'A'..'Z', 'a'..'z', '_', '%']) do Inc(Index); Result := Copy(Str, IndexStart, Index - IndexStart); end; var IndexInput, IndexOutput, TokenPos, CharCountIn, CharCountOut, IfCount, StrIndex, RepeatCount: Integer; Identifier, Command, Symbol, StrValue, RepeatPattern, RepeatValue: string; StrList: TStrings; begin CharCountIn := Length(Template); CharCountOut := 2*CharCountIn; SetLength(Result, CharCountOut); IndexInput := 1; IndexOutput := 1; IfCount := 0; while IndexInput < CharCountIn do begin TokenPos := CharPos(Template, '%', IndexInput); if TokenPos = 0 then begin CopyStr(Result, IndexOutput, CharCountOut, Template, IndexInput, CharCountIn - IndexInput + 1); SetLength(Result, IndexOutput - 1); Exit; end else begin if IfCount = 0 then CopyStr(Result, IndexOutput, CharCountOut, Template, IndexInput, TokenPos - IndexInput); Identifier := GetIdentifier(Template, TokenPos, CharCountIn); Command := StrUpper(Identifier); if Command = '%IF' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if (IfCount > 0) or not Params.IsDefined(Symbol) then begin Inc(IfCount); end; end else if Command = '%IFNOT' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if (IfCount > 0) or Params.IsDefined(Symbol) then Inc(IfCount); end else if Command = '%ELSE' then begin if IfCount = 1 then IfCount := 0 else if IfCount = 0 then IfCount := 1; end else if Command = '%ENDIF' then begin if IfCount > 0 then Dec(IfCount); end else if Command = '%STRVALUE' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if IfCount = 0 then begin StrValue := Params.GetStrValue(Symbol); case Params.Language of bpDelphi32: begin StrValue := StringReplace(StrValue, AnsiSingleQuote, AnsiSingleQuote + AnsiSingleQuote, [rfReplaceAll]); StrValue := AnsiSingleQuote + StrValue + AnsiSingleQuote; end; bpBCBuilder32: begin StrValue := StringReplace(StrValue, AnsiDoubleQuote, AnsiBackslash + AnsiDoubleQuote, [rfReplaceAll]); StrValue := AnsiDoubleQuote + StrValue + AnsiDoubleQuote; end; end; CopyStr(Result, IndexOutput, CharCountOut, StrValue, 1, Length(StrValue)); end; end else if Command = '%INTVALUE' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if IfCount = 0 then begin StrValue := IntToStr(Params.GetIntValue(Symbol)); CopyStr(Result, IndexOutput, CharCountOut, StrValue, 1, Length(StrValue)); end; end else if Command = '%BOOLVALUE' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if IfCount = 0 then begin StrValue := BooleanToStr(Params.GetBoolValue(Symbol)); CopyStr(Result, IndexOutput, CharCountOut, StrValue, 1, Length(StrValue)); end; end else if Command = '%REPEATLINE' then begin TokenPos := SkipBlanks(Template, TokenPos, CharCountIn); Symbol := GetIdentifier(Template, TokenPos, CharCountIn); if IfCount = 0 then begin RepeatCount := Params.GetIntValue(Symbol); StrIndex := TokenPos; while (StrIndex <= CharCountIn) and not (Template[StrIndex] in [AnsiLineFeed, AnsiCarriageReturn]) do Inc(StrIndex); RepeatPattern := Copy(Template, TokenPos, StrIndex - TokenPos); TokenPos := StrIndex; while RepeatCount > 0 do begin StrValue := RepeatPattern; StrIndex := Pos('%', StrValue); while StrIndex > 0 do begin Inc(StrIndex); Symbol := GetIdentifier(StrValue, StrIndex, Length(StrValue)); StrList := Params.GetStringsValue(Symbol); if Assigned(StrList) then RepeatValue := StrList.Strings[RepeatCount - 1] else RepeatValue := ''; StrReplace(StrValue, '%' + Symbol, RepeatValue, [rfReplaceAll, rfIgnoreCase]); StrIndex := Pos('%', StrValue); end; CopyStr(Result, IndexOutput, CharCountOut, StrValue, 1, Length(StrValue)); CopyStr(Result, IndexOutput, CharCountOut, AnsiLineBreak, 1, Length(AnsiLineBreak)); Dec(RepeatCount); end; end; end else if IfCount = 0 then CopyStr(Result, IndexOutput, CharCountOut, Identifier, 1, Length(Identifier)); IndexInput := TokenPos; end; end; end; //=== { TJclOtaTemplateParams } ============================================== function TJclOtaTemplateParams.GetBoolValue(const Name: string): Boolean; var VariantValue: Variant; begin VariantValue := GetPropValue(Self, Name); Result := Boolean(VariantValue); end; function TJclOtaTemplateParams.GetIntValue(const Name: string): Integer; var VariantValue: Variant; begin VariantValue := GetPropValue(Self, Name); Result := Integer(VariantValue); end; function TJclOtaTemplateParams.GetStringsValue(const Name: string): TStrings; var Instance: TObject; begin Instance := TObject(GetOrdProp(Self, Name)); if Instance is TStrings then Result := TStrings(Instance) else Result := nil; end; function TJclOtaTemplateParams.GetStrValue(const Name: string): string; var VariantValue: Variant; begin VariantValue := GetPropValue(Self, Name, True); Result := string(VariantValue); end; function TJclOtaTemplateParams.IsDefined(const Name: string): Boolean; begin Result := GetBoolValue(Name); end; end.