From 81c5688893cfc551750c74bb75d285248cf1a05a Mon Sep 17 00:00:00 2001 From: michael Date: Sun, 18 Apr 2021 10:45:47 +0000 Subject: * Fix issue ID 38772 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49225 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/objpas/sysutils/osutil.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/objpas/sysutils/osutil.inc b/rtl/objpas/sysutils/osutil.inc index ffa7531efd..729f96d285 100644 --- a/rtl/objpas/sysutils/osutil.inc +++ b/rtl/objpas/sysutils/osutil.inc @@ -245,7 +245,7 @@ begin Repeat Result:=Format('%s%.5d.tmp',[Start,I]); Inc(I); - Until not FileExists(Result); + Until not (FileExists(Result) or DirectoryExists(Result)); end; end; {$endif} -- cgit v1.2.1 From a3180d0319583e62620eb80ccabe0614940fa17b Mon Sep 17 00:00:00 2001 From: mattias Date: Sun, 18 Apr 2021 12:51:54 +0000 Subject: pas2js: fixed delay init specializations after loading impl sections git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49226 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/pastojs/src/fppas2js.pp | 63 ++++++++++++++++++---------- packages/pastojs/tests/tcgenerics.pas | 78 ++++++++++++++++++++++++++++++----- packages/pastojs/tests/testpas2js.pp | 2 +- 3 files changed, 111 insertions(+), 32 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 4c7c9ffdf2..bb222fd720 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -2082,8 +2082,8 @@ type Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual; Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual; Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual; - Procedure AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual; - Procedure AddDelaySpecializeInit(El: TPasGenericType; Src: TJSSourceElements; AContext: TConvertContext); virtual; + function AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext): boolean; virtual; + function CreateDelaySpecializeInit(El: TPasGenericType; AContext: TConvertContext): TJSElement; virtual; // enum and sets Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual; // record @@ -8199,7 +8199,7 @@ Var ModuleName, ModVarName: String; IntfContext: TSectionContext; ImplVarSt: TJSVariableStatement; - HasImplUsesClause, ok, NeedRTLCheckVersion: Boolean; + HasImplCode, ok, NeedRTLCheckVersion: Boolean; Prg: TPasProgram; Lib: TPasLibrary; ImplFuncAssignSt: TJSSimpleAssignStatement; @@ -8280,7 +8280,7 @@ begin Prg:=TPasProgram(El); if Assigned(Prg.ProgramSection) then AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext)); - AddDelayedInits(Prg,Src,IntfContext); + HasImplCode:=AddDelayedInits(Prg,Src,IntfContext); CreateInitSection(Prg,Src,IntfContext); end else if El is TPasLibrary then @@ -8288,7 +8288,7 @@ begin Lib:=TPasLibrary(El); if Assigned(Lib.LibrarySection) then AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext)); - AddDelayedInits(Lib,Src,IntfContext); + HasImplCode:=AddDelayedInits(Lib,Src,IntfContext); CreateInitSection(Lib,Src,IntfContext); // ToDo: append exports end @@ -8317,7 +8317,9 @@ begin // append initialization section CreateInitSection(El,Src,IntfSecCtx); - if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count=0 then + if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count>0 then + HasImplCode:=true + else begin // empty implementation @@ -8325,18 +8327,14 @@ begin RemoveFromSourceElements(Src,ImplVarSt); // remove unneeded $mod.$implcode = function(){} RemoveFromSourceElements(Src,ImplFuncAssignSt); - HasImplUsesClause:=(El.ImplementationSection<>nil) + // keep impl uses section + HasImplCode:=(El.ImplementationSection<>nil) and (length(El.ImplementationSection.UsesClause)>0); - end - else - begin - HasImplUsesClause:=true; end; - if HasImplUsesClause then + if HasImplCode then // add implementation uses list: [,, ...] ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext)); - end; // end unit if (ModScope<>nil) and (coStoreImplJS in Options) then @@ -17846,13 +17844,18 @@ begin IntfSec.AddImplHeaderStatement(JS); end; -procedure TPasToJSConverter.AddDelayedInits(El: TPasModule; - Src: TJSSourceElements; AContext: TConvertContext); +function TPasToJSConverter.AddDelayedInits(El: TPasModule; + Src: TJSSourceElements; AContext: TConvertContext): boolean; var aResolver: TPas2JSResolver; Hub: TPas2JSResolverHub; i: Integer; + JS: TJSElement; + AssignSt: TJSSimpleAssignStatement; + FunDecl: TJSFunctionDeclarationStatement; + ImplSrc: TJSSourceElements; begin + Result:=false; aResolver:=AContext.Resolver; if aResolver=nil then exit; if El=nil then ; @@ -17860,12 +17863,29 @@ begin {$IFDEF VerbosePas2JS} writeln('TPasToJSConverter.AddDelayedInits Hub.JSDelaySpecializeCount=',Hub.JSDelaySpecializeCount); {$ENDIF} + ImplSrc:=nil; for i:=0 to Hub.JSDelaySpecializeCount-1 do - AddDelaySpecializeInit(Hub.JSDelaySpecializes[i],Src,AContext); + begin + JS:=CreateDelaySpecializeInit(Hub.JSDelaySpecializes[i],AContext); + if JS=nil then continue; + if ImplSrc=nil then + begin + // create "$mod.$implcode = function(){ }" + AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); + AddToSourceElements(Src,AssignSt); + AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnModule),GetBIName(pbivnImplCode)]); + // create function(){} + FunDecl:=CreateFunctionSt(El,true,true); + AssignSt.Expr:=FunDecl; + ImplSrc:=TJSSourceElements(FunDecl.AFunction.Body.A); + end; + AddToSourceElements(ImplSrc,JS); + Result:=true; + end; end; -procedure TPasToJSConverter.AddDelaySpecializeInit(El: TPasGenericType; - Src: TJSSourceElements; AContext: TConvertContext); +function TPasToJSConverter.CreateDelaySpecializeInit(El: TPasGenericType; + AContext: TConvertContext): TJSElement; var C: TClass; Path: String; @@ -17876,6 +17896,7 @@ var ElTypeHi, ElTypeLo: TPasType; aResolver: TPas2JSResolver; begin + Result:=nil; if not IsElementUsed(El) then exit; if not AContext.Resolver.IsFullySpecialized(El) then RaiseNotSupported(El,AContext,20201202145045,'not fully specialized, probably a bug in the analyzer'); @@ -17889,7 +17910,7 @@ begin Path:=CreateReferencePath(El,AContext,rpkPathAndName)+'.'+GetBIName(pbifnClassInitSpecialize); Call:=CreateCallExpression(El); Call.Expr:=CreatePrimitiveDotExpr(Path,El); - AddToSourceElements(Src,Call); + Result:=Call; end else if (C=TPasProcedureType) or (C=TPasFunctionType) then begin @@ -17901,7 +17922,7 @@ begin DotExpr.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec)); Call:=CreateCallExpression(El); Call.Expr:=DotExpr; - AddToSourceElements(Src,Call); + Result:=Call; end else if (C=TPasArrayType) then begin @@ -17928,7 +17949,7 @@ begin AssignSt.LHS:=CreateDotNameExpr(El,CreateTypeInfoRef(El,AContext,El), TJSString(GetBIName(pbivnRTTIArray_ElType))); AssignSt.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El); - AddToSourceElements(Src,AssignSt); + Result:=AssignSt; end else RaiseNotSupported(El,AContext,20200831115251); diff --git a/packages/pastojs/tests/tcgenerics.pas b/packages/pastojs/tests/tcgenerics.pas index 1f486d4d9f..8b1c961aa3 100644 --- a/packages/pastojs/tests/tcgenerics.pas +++ b/packages/pastojs/tests/tcgenerics.pas @@ -20,7 +20,7 @@ type Procedure TestGen_Record_ClassVarRecord_Program; Procedure TestGen_Record_ClassVarRecord_UnitImpl; Procedure TestGen_Record_RTTI_UnitImpl; - // ToDo: delay RTTI with anonymous array a:array of T, array[1..2] of T + procedure TestGen_Record_Delay_UsedByImplUses; // ToDo: type alias type as parameter, TBird = type word; // generic class @@ -288,7 +288,9 @@ begin '}, []);'])); CheckSource('TestGen_Record_ClassVarRecord_UnitImpl', LinesToStr([ // statements - 'pas.UnitA.TAnt$G1.$initSpec();', + '$mod.$implcode = function () {', + ' pas.UnitA.TAnt$G1.$initSpec();', + '};', '']), LinesToStr([ // $mod.$main ''])); @@ -355,6 +357,53 @@ begin ''])); end; +procedure TTestGenerics.TestGen_Record_Delay_UsedByImplUses; +begin + WithTypeInfo:=true; + StartProgram(true,[supTObject]); + AddModuleWithIntfImplSrc('UnitA.pas', + LinesToStr([ + '{$modeswitch AdvancedRecords}', + 'type', + ' generic TBird = record', + ' class var a: T;', + ' end;', + '']), + LinesToStr([ + ''])); + AddModuleWithIntfImplSrc('UnitB.pas', + LinesToStr([ + 'procedure Fly;', + '']), + LinesToStr([ + 'uses UnitA;', + 'type', + ' TFox = record', + ' B: word;', + ' end;', + 'procedure Fly;', + 'var Bird: specialize TBird;', + 'begin', + ' if typeinfo(Bird)<>nil then ;', + ' Bird.a:=Bird.a;', + 'end;', + ''])); + Add([ + 'uses UnitB;', + 'begin', + ' Fly;']); + ConvertProgram; + CheckSource('TestGen_Record_Delay_UsedByImplUses', + LinesToStr([ // statements + '$mod.$implcode = function () {', + ' pas.UnitA.TBird$G1.$initSpec();', + '};', + '']), + LinesToStr([ // $mod.$main + 'pas.UnitB.Fly();' + ])); +end; + procedure TTestGenerics.TestGen_ClassEmpty; begin StartProgram(false); @@ -1201,7 +1250,9 @@ begin ''])); CheckSource('TestGen_Class_ClassVarRecord_UnitImpl', LinesToStr([ // statements - 'pas.UnitA.TAnt$G1.$initSpec();', + '$mod.$implcode = function () {', + ' pas.UnitA.TAnt$G1.$initSpec();', + '};', '']), LinesToStr([ // $mod.$main ''])); @@ -1453,7 +1504,6 @@ begin '}, []);'])); CheckSource('TestGen_Class_ClassVarRecord_UnitImpl', LinesToStr([ // statements - //'pas.UnitA.TAnt$G1.$initSpec();', '']), LinesToStr([ // $mod.$main ''])); @@ -1706,7 +1756,9 @@ begin ' rtl.addIntf(this, pas.system.IUnknown);', '});', 'this.i = null;', - 'pas.UnitA.TAnt$G1.$initSpec();', + '$mod.$implcode = function () {', + ' pas.UnitA.TAnt$G1.$initSpec();', + '};', '']), LinesToStr([ // $mod.$main 'rtl.setIntfP($mod, "i", rtl.queryIntfT($mod.TBird.$create("Create"), pas.UnitA.TAnt$G1), true);', @@ -2424,7 +2476,9 @@ begin '});'])); CheckSource('TestGen_Array_OtherUnit', LinesToStr([ // statements - 'pas.UnitA.$rtti["TDyn"].eltype = pas.UnitB.$rtti["TAnt"];', + '$mod.$implcode = function () {', + ' pas.UnitA.$rtti["TDyn"].eltype = pas.UnitB.$rtti["TAnt"];', + '};', '']), LinesToStr([ // $mod.$main ' pas.UnitB.Run();', @@ -2504,9 +2558,11 @@ begin '}, []);'])); CheckSource('TestGen_ArrayOfUnitImplRec', LinesToStr([ // statements - 'pas.UnitA.$rtti["TDyn"].eltype = pas.UnitA.$rtti["TAnt"];', - 'pas.UnitA.$rtti["TDyn"].eltype = pas.UnitA.$rtti["TBird"];', - 'pas.UnitA.$rtti["TStatic"].eltype = pas.UnitA.$rtti["TBird"];', + '$mod.$implcode = function () {', + ' pas.UnitA.$rtti["TDyn"].eltype = pas.UnitA.$rtti["TAnt"];', + ' pas.UnitA.$rtti["TDyn"].eltype = pas.UnitA.$rtti["TBird"];', + ' pas.UnitA.$rtti["TStatic"].eltype = pas.UnitA.$rtti["TBird"];', + '};', '']), LinesToStr([ // $mod.$main ''])); @@ -2673,7 +2729,9 @@ begin '}, []);'])); CheckSource('TestGen_Class_ClassVarRecord_UnitImpl', LinesToStr([ // statements - 'pas.UnitA.$rtti["TAnt"].init();', + '$mod.$implcode = function () {', + ' pas.UnitA.$rtti["TAnt"].init();', + '};', '']), LinesToStr([ // $mod.$main ''])); diff --git a/packages/pastojs/tests/testpas2js.pp b/packages/pastojs/tests/testpas2js.pp index 0437a3978c..dff9b3ccc0 100644 --- a/packages/pastojs/tests/testpas2js.pp +++ b/packages/pastojs/tests/testpas2js.pp @@ -21,7 +21,7 @@ uses MemCheck, {$ENDIF} Classes, consoletestrunner, tcconverter, TCModules, TCSrcMap, - TCFiler, TCUnitSearch, TCOptimizations, TCGenerics, TCPrecompile; + TCFiler, TCUnitSearch, TCOptimizations, TCGenerics, TCPrecompile, unit2; type -- cgit v1.2.1 From c9d8f8a378ad21ab2b306d2103390f2a2725f558 Mon Sep 17 00:00:00 2001 From: mattias Date: Sun, 18 Apr 2021 12:59:48 +0000 Subject: pastojs: clean up git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49227 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/pastojs/tests/testpas2js.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pastojs/tests/testpas2js.pp b/packages/pastojs/tests/testpas2js.pp index dff9b3ccc0..0437a3978c 100644 --- a/packages/pastojs/tests/testpas2js.pp +++ b/packages/pastojs/tests/testpas2js.pp @@ -21,7 +21,7 @@ uses MemCheck, {$ENDIF} Classes, consoletestrunner, tcconverter, TCModules, TCSrcMap, - TCFiler, TCUnitSearch, TCOptimizations, TCGenerics, TCPrecompile, unit2; + TCFiler, TCUnitSearch, TCOptimizations, TCGenerics, TCPrecompile; type -- cgit v1.2.1 From e671ec0a81414c6a568fec0653f9d82202e0d95f Mon Sep 17 00:00:00 2001 From: svenbarth Date: Sun, 18 Apr 2021 14:01:09 +0000 Subject: * fix for Mantis #38771: the owner of the procdef might be Nil in case of a specialization (that virtual can't be used on generics is caught later on) + added test git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49228 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/pdecsub.pas | 3 ++- tests/webtbf/tw38771.pp | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/webtbf/tw38771.pp diff --git a/compiler/pdecsub.pas b/compiler/pdecsub.pas index b7ce1fda75..5dcb4ad8a7 100644 --- a/compiler/pdecsub.pas +++ b/compiler/pdecsub.pas @@ -1959,7 +1959,8 @@ var pt : tnode; {$endif WITHDMT} begin - if (not assigned(pd.owner.defowner) or + if assigned(pd.owner) and + (not assigned(pd.owner.defowner) or not is_java_class_or_interface(tdef(pd.owner.defowner))) and (po_external in pd.procoptions) then Message2(parser_e_proc_dir_conflict,'EXTERNAL','"VIRTUAL"'); diff --git a/tests/webtbf/tw38771.pp b/tests/webtbf/tw38771.pp new file mode 100644 index 0000000000..1d041847a2 --- /dev/null +++ b/tests/webtbf/tw38771.pp @@ -0,0 +1,22 @@ +{ %FAIL } +{$mode objfpc} + +program tw38771; + +type + TMyClass = class + generic procedure DoThis(msg: T); + generic procedure DoThat(msg: T); virtual; + end; + +generic procedure TMyClass.DoThis(msg:T); +begin + specialize DoThat(msg); +end; + +generic procedure TMyClass.DoThat(msg: T); +begin +end; + +begin +end. -- cgit v1.2.1 From d29154ba904dfa0d1284d1b4d5dcd486100ecd91 Mon Sep 17 00:00:00 2001 From: pierre Date: Sun, 18 Apr 2021 15:41:11 +0000 Subject: Add systems_openbsd to suppported_targets_x_smallr and modify GenerateExecutable in t_bsd unit accordingly git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49229 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/options.pas | 1 + compiler/systems/t_bsd.pas | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/options.pas b/compiler/options.pas index d10709ed21..ba299ca140 100644 --- a/compiler/options.pas +++ b/compiler/options.pas @@ -140,6 +140,7 @@ const suppported_targets_x_smallr = systems_linux + systems_solaris + systems_android + + systems_openbsd + [system_i386_haiku,system_x86_64_haiku] + [system_i386_beos] + [system_m68k_amiga]; diff --git a/compiler/systems/t_bsd.pas b/compiler/systems/t_bsd.pas index 915e57be82..99a4b8ca97 100644 --- a/compiler/systems/t_bsd.pas +++ b/compiler/systems/t_bsd.pas @@ -482,12 +482,14 @@ begin (tf_smartlink_sections in target_info.flags) then GCSectionsStr:='--gc-sections'; - if(cs_profile in current_settings.moduleswitches) or + if (cs_profile in current_settings.moduleswitches) or ((Info.DynamicLinker<>'') and ((not SharedLibFiles.Empty) or (target_info.system in systems_openbsd))) then - DynLinkStr:='-dynamic-linker='+Info.DynamicLinker; + DynLinkStr:='-dynamic-linker='+Info.DynamicLinker; + if rlinkpath<>'' then + DynLinkStr:=DynLinkStr+' --rpath-link '+rlinkpath; if CShared Then begin DynLinKStr:=DynLinkStr+' --shared' -- cgit v1.2.1 From 0f8b41331592face5c178226bf33a1faa8588f74 Mon Sep 17 00:00:00 2001 From: pierre Date: Sun, 18 Apr 2021 15:44:07 +0000 Subject: Handle NIL entries in deflist after commit 48986 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49230 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/pgenutil.pas | 3 +++ compiler/pmodules.pas | 3 +++ compiler/wasm32/agllvmmc.pas | 45 ++++++++++++++++++++++++-------------------- compiler/wasm32/agwat.pas | 7 +++++-- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/compiler/pgenutil.pas b/compiler/pgenutil.pas index 4804995dbb..1829ce335a 100644 --- a/compiler/pgenutil.pas +++ b/compiler/pgenutil.pas @@ -813,6 +813,9 @@ uses st : TSymtable; i : longint; begin + { since commit 48986 deflist might have NIL entries } + if not assigned(def) then + exit; case def.typ of procdef: tprocdef(def).forwarddef:=false; diff --git a/compiler/pmodules.pas b/compiler/pmodules.pas index 60f93e6ae4..d5037f7d60 100644 --- a/compiler/pmodules.pas +++ b/compiler/pmodules.pas @@ -618,6 +618,9 @@ implementation for i:=current_module.localsymtable.deflist.count-1 downto 0 do begin def:=tdef(current_module.localsymtable.deflist[i]); + { since commit 48986 deflist might have NIL entries } + if not assigned(def) then + continue; { this also frees def, as the defs are owned by the symtable } if not def.is_registered and not(df_not_registered_no_free in def.defoptions) then diff --git a/compiler/wasm32/agllvmmc.pas b/compiler/wasm32/agllvmmc.pas index 4468a56f27..95db60e14b 100644 --- a/compiler/wasm32/agllvmmc.pas +++ b/compiler/wasm32/agllvmmc.pas @@ -70,31 +70,36 @@ implementation procedure TLLVMMachineCodePlaygroundAssembler.WriteImports; var i : integer; + def : tdef; proc : tprocdef; list : TAsmList; cur_unit: tused_unit; begin for i:=0 to current_module.deflist.Count-1 do - if assigned(current_module.deflist[i]) and (tdef(current_module.deflist[i]).typ=procdef) then - begin - proc := tprocdef(current_module.deflist[i]); - if (po_external in proc.procoptions) and assigned(proc.import_dll) then - begin - //WriteProcDef(proc); - list:=TAsmList.Create; - thlcgwasm(hlcg).g_procdef(list,proc); - WriteTree(list); - list.free; - writer.AsmWrite(#9'.import_module'#9); - writer.AsmWrite(proc.mangledname); - writer.AsmWrite(', '); - writer.AsmWriteLn(proc.import_dll^); - writer.AsmWrite(#9'.import_name'#9); - writer.AsmWrite(proc.mangledname); - writer.AsmWrite(', '); - writer.AsmWriteLn(proc.import_name^); - end; - end; + begin + def:=tdef(current_module.deflist[i]); + { since commit 48986 deflist might have NIL entries } + if assigned(def) and (def.typ=procdef) then + begin + proc := tprocdef(def); + if (po_external in proc.procoptions) and assigned(proc.import_dll) then + begin + //WriteProcDef(proc); + list:=TAsmList.Create; + thlcgwasm(hlcg).g_procdef(list,proc); + WriteTree(list); + list.free; + writer.AsmWrite(#9'.import_module'#9); + writer.AsmWrite(proc.mangledname); + writer.AsmWrite(', '); + writer.AsmWriteLn(proc.import_dll^); + writer.AsmWrite(#9'.import_name'#9); + writer.AsmWrite(proc.mangledname); + writer.AsmWrite(', '); + writer.AsmWriteLn(proc.import_name^); + end; + end; + end; list:=TAsmList.Create; cur_unit:=tused_unit(usedunits.First); while assigned(cur_unit) do diff --git a/compiler/wasm32/agwat.pas b/compiler/wasm32/agwat.pas index 7d40c64936..13684044dd 100644 --- a/compiler/wasm32/agwat.pas +++ b/compiler/wasm32/agwat.pas @@ -957,14 +957,17 @@ implementation procedure TWabtTextAssembler.WriteImports; var i : integer; + def : tdef; proc : tprocdef; sym : tsym; j : integer; psym : tprocsym; begin for i:=0 to current_module.deflist.Count-1 do begin - if tdef(current_module.deflist[i]).typ = procdef then begin - proc := tprocdef(current_module.deflist[i]); + def:=tdef(current_module.deflist[i]); + { since commit 48986 deflist might have NIL entries } + if assigned(def) and (def.typ=procdef) then begin + proc := tprocdef(def); if (po_external in proc.procoptions) and assigned(proc.import_dll) then begin writer.AsmWrite(#9'(import "'); writer.AsmWrite(proc.import_dll^); -- cgit v1.2.1 From c1d5f73581c42ac0ea57f3b0d5e41d6e5c800357 Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 18 Apr 2021 19:19:35 +0000 Subject: * if left is a smaller type, then an extension operation for shr can be removed git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49231 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/ncnv.pas | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/compiler/ncnv.pas b/compiler/ncnv.pas index 4182b2d3ad..f115685a3d 100644 --- a/compiler/ncnv.pas +++ b/compiler/ncnv.pas @@ -2948,6 +2948,11 @@ implementation gotsint:=true; result:=docheckremoveinttypeconvs(tunarynode(n).left); end; + shrn: + begin + result:=wasoriginallysmallerint(tbinarynode(n).left) and + docheckremoveinttypeconvs(tbinarynode(n).right); + end; notn: result:=docheckremoveinttypeconvs(tunarynode(n).left); addn,muln,divn,modn,andn,shln: @@ -2981,15 +2986,26 @@ implementation { remove int type conversions and set the result to the given type } - procedure doremoveinttypeconvs(var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef); + procedure doremoveinttypeconvs(level : dword;var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef); var newblock: tblocknode; newstatements: tstatementnode; originaldivtree: tnode; tempnode: ttempcreatenode; begin + { we may not recurse into shr nodes: + + dword1:=dword1+((dword2+dword3) shr 2); + + while we can remove an extension on the addition, we cannot remove it from the shr + } + if (n.nodetype=shrn) and (level<>0) then + begin + inserttypeconv_internal(n,todef); + exit; + end; case n.nodetype of - subn,addn,muln,divn,modn,xorn,andn,orn,shln: + subn,addn,muln,divn,modn,xorn,andn,orn,shln,shrn: begin exclude(n.flags,nf_internal); if not forceunsigned and @@ -2998,8 +3014,8 @@ implementation originaldivtree:=nil; if n.nodetype in [divn,modn] then originaldivtree:=n.getcopy; - doremoveinttypeconvs(tbinarynode(n).left,signedtype,false,signedtype,unsignedtype); - doremoveinttypeconvs(tbinarynode(n).right,signedtype,false,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tbinarynode(n).left,signedtype,false,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tbinarynode(n).right,signedtype,false,signedtype,unsignedtype); n.resultdef:=signedtype; if n.nodetype in [divn,modn] then begin @@ -3026,8 +3042,8 @@ implementation end else begin - doremoveinttypeconvs(tbinarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype); - doremoveinttypeconvs(tbinarynode(n).right,unsignedtype,forceunsigned,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tbinarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tbinarynode(n).right,unsignedtype,forceunsigned,signedtype,unsignedtype); n.resultdef:=unsignedtype; end; //if ((n.nodetype=andn) and (tbinarynode(n).left.nodetype=ordconstn) and @@ -3044,12 +3060,12 @@ implementation if not forceunsigned and is_signed(n.resultdef) then begin - doremoveinttypeconvs(tunarynode(n).left,signedtype,false,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tunarynode(n).left,signedtype,false,signedtype,unsignedtype); n.resultdef:=signedtype; end else begin - doremoveinttypeconvs(tunarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype); + doremoveinttypeconvs(level+1,tunarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype); n.resultdef:=unsignedtype; end; end; @@ -3344,22 +3360,22 @@ implementation to 64 bit } if (resultdef.size <= 4) and is_64bitint(left.resultdef) and - (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and + (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln,shrn]) and checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit,s32bit,u32bit],int64(low(longint)),high(cardinal)) then - doremoveinttypeconvs(left,generrordef,not foundsint,s32inttype,u32inttype); + doremoveinttypeconvs(0,left,generrordef,not foundsint,s32inttype,u32inttype); {$if defined(cpu16bitalu)} if (resultdef.size <= 2) and (is_32bitint(left.resultdef) or is_64bitint(left.resultdef)) and - (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and + (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln,shrn]) and checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit],int64(low(smallint)),high(word)) then - doremoveinttypeconvs(left,generrordef,not foundsint,s16inttype,u16inttype); + doremoveinttypeconvs(0,left,generrordef,not foundsint,s16inttype,u16inttype); {$endif defined(cpu16bitalu)} {$if defined(cpu8bitalu)} if (resultdef.size Date: Mon, 19 Apr 2021 05:42:18 +0000 Subject: sinclairql: hopefully fix off-by-one processing in the packed relocs code git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49232 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/sinclairql/si_prc.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/sinclairql/si_prc.pp b/rtl/sinclairql/si_prc.pp index 0d4133ee82..95993c65fe 100644 --- a/rtl/sinclairql/si_prc.pp +++ b/rtl/sinclairql/si_prc.pp @@ -107,7 +107,7 @@ asm add.l d1,d2 add.l d0,(a0,d2) subq.l #1,d7 - bpl @relocloop + bgt @relocloop {$ENDIF PACKEDRELOCS} @noreloc: -- cgit v1.2.1 From 0f102c98fad0386770958401226d2cb88793a4ad Mon Sep 17 00:00:00 2001 From: karoly Date: Mon, 19 Apr 2021 09:13:02 +0000 Subject: m68k: added support to references like (a0,d0.w) in inline assembly, also fixed a bug, where sometimes the index register would have been randomly set as smaller than .l size, when the size wasn't specified git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49233 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/m68k/cpubase.pas | 8 ++++++++ compiler/m68k/r68kgri.inc | 16 ++++++++-------- compiler/m68k/r68ksri.inc | 36 ++++++++++++++++++------------------ compiler/m68k/ra68kmot.pas | 7 ++++++- compiler/utils/mk68kreg.pp | 4 ++-- 5 files changed, 42 insertions(+), 29 deletions(-) diff --git a/compiler/m68k/cpubase.pas b/compiler/m68k/cpubase.pas index 6ecf62ec53..cf592f19a2 100644 --- a/compiler/m68k/cpubase.pas +++ b/compiler/m68k/cpubase.pas @@ -331,6 +331,10 @@ implementation {$i r68kstd.inc} ); + std_regfullname_table : TRegNameTable = ( + {$i r68kstdf.inc} + ); + regnumber_index : array[tregisterindex] of tregisterindex = ( {$i r68krni.inc} ); @@ -484,6 +488,10 @@ implementation function std_regnum_search(const s:string):Tregister; begin result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)]; + if result=NR_NO then + begin + result:=regnumber_table[findreg_by_name_table(s,std_regfullname_table,std_regname_index)]; + end; end; diff --git a/compiler/m68k/r68kgri.inc b/compiler/m68k/r68kgri.inc index 0e386d3f1a..31c8bf302e 100644 --- a/compiler/m68k/r68kgri.inc +++ b/compiler/m68k/r68kgri.inc @@ -16,30 +16,30 @@ 56, 57, 34, +3, 1, 2, -3, +6, 4, 5, -6, +9, 7, 8, -9, 12, -11, 10, +11, +15, 13, 14, -15, +18, 16, 17, -18, +21, 19, 20, -21, 24, -23, 22, +23, 38, 25, 26, diff --git a/compiler/m68k/r68ksri.inc b/compiler/m68k/r68ksri.inc index 47fd3b2f30..0f66a7b772 100644 --- a/compiler/m68k/r68ksri.inc +++ b/compiler/m68k/r68ksri.inc @@ -1,46 +1,46 @@ { don't edit, this file is generated from m68kreg.dat } 0, -43, 42, -45, +43, 44, -47, +45, 46, -49, +47, 48, -51, +49, 50, -53, +51, 52, -55, +53, 54, -57, +55, 56, +57, 34, -1, 3, +1, 2, -5, -4, 6, -7, +4, +5, 9, +7, 8, -11, 12, 10, -13, +11, 15, +13, 14, -17, -16, 18, -19, +16, +17, 21, +19, 20, -23, 24, 22, +23, 38, 25, 26, diff --git a/compiler/m68k/ra68kmot.pas b/compiler/m68k/ra68kmot.pas index ba7f0a3b4e..184a9742ae 100644 --- a/compiler/m68k/ra68kmot.pas +++ b/compiler/m68k/ra68kmot.pas @@ -216,6 +216,11 @@ const actasmregister:=std_regnum_search(lower(s)); if actasmregister<>NR_NO then begin + { this is a hack. if the reg is valid, and its string doesn't + contain a dot, we make sure it's a full size reg (KB) } + if (getregtype(actasmregister) in [R_ADDRESSREGISTER,R_INTREGISTER]) and + (Pos('.',s) = 0) then + setsubreg(actasmregister,R_SUBWHOLE); result:=true; actasmtoken:=AS_REGISTER; end; @@ -1196,7 +1201,7 @@ const while actasmtoken <> AS_SEPARATOR do Consume(actasmtoken); end; - exit; + exit; end; { // (reg,reg .. // } Consume(AS_COMMA); diff --git a/compiler/utils/mk68kreg.pp b/compiler/utils/mk68kreg.pp index 3cd6d19c40..59c9445811 100644 --- a/compiler/utils/mk68kreg.pp +++ b/compiler/utils/mk68kreg.pp @@ -133,7 +133,7 @@ begin i:=h; repeat j:=i+p; - if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then + if stdfullnames[std_regname_index[j]]>=stdfullnames[std_regname_index[i]] then break; t:=std_regname_index[i]; std_regname_index[i]:=std_regname_index[j]; @@ -164,7 +164,7 @@ begin i:=h; repeat j:=i+p; - if gasnames[gas_regname_index[j]]>=gasnames[gas_regname_index[i]] then + if gasfullnames[gas_regname_index[j]]>=gasfullnames[gas_regname_index[i]] then break; t:=gas_regname_index[i]; gas_regname_index[i]:=gas_regname_index[j]; -- cgit v1.2.1 From 8e6c0f149ad55bf103b20a5a1a7e8bf42ca787f5 Mon Sep 17 00:00:00 2001 From: karoly Date: Mon, 19 Apr 2021 19:09:34 +0000 Subject: sinclairql: support the upcoming QL binary linking feature of vlink (still in development). it's behind an undocumented -WL switch now. also, reduce the amount of used dataspace by the size of the relocation table in the current linking mode git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49234 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/globals.pas | 1 + compiler/options.pas | 7 +++++++ compiler/systems/t_sinclairql.pas | 19 ++++++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/globals.pas b/compiler/globals.pas index f26979d83b..ab570352a6 100644 --- a/compiler/globals.pas +++ b/compiler/globals.pas @@ -416,6 +416,7 @@ interface {$if defined(m68k)} { Sinclair QL specific } sinclairql_metadata_format: string[4] = 'QHDR'; + sinclairql_vlink_experimental: boolean = false; { temporary } {$endif defined(m68k)} { default name of the C-style "main" procedure of the library/program } diff --git a/compiler/options.pas b/compiler/options.pas index ba299ca140..990e92dda8 100644 --- a/compiler/options.pas +++ b/compiler/options.pas @@ -2761,6 +2761,13 @@ begin IllegalPara(opt); end; {$if defined(m68k)} + 'L': + begin + if (target_info.system in [system_m68k_sinclairql]) then + sinclairql_vlink_experimental:=true + else + IllegalPara(opt); + end; 'Q': begin if (target_info.system in [system_m68k_sinclairql]) then diff --git a/compiler/systems/t_sinclairql.pas b/compiler/systems/t_sinclairql.pas index 1e16e4ebab..444fd3aa5b 100644 --- a/compiler/systems/t_sinclairql.pas +++ b/compiler/systems/t_sinclairql.pas @@ -115,7 +115,7 @@ begin end else begin - ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES'; + ExeCmd[1]:='vlink $QLFLAGS $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES'; end; end; end; @@ -245,6 +245,7 @@ var DynLinkStr : string; GCSectionsStr : string; FlagsStr : string; + QLFlagsStr: string; MapStr : string; ExeName: string; fd,fs: file; @@ -258,6 +259,7 @@ var QLHeader: TQLHeader; XTccData: TXTccData; BinSize: longint; + RelocSize: longint; DataSpace: DWord; begin StripStr:=''; @@ -276,6 +278,10 @@ begin begin if create_smartlink_sections then GCSectionsStr:='-gc-all'; + if sinclairql_vlink_experimental then + QLFlagsStr:='-b sinclairql -q -'+lower(sinclairql_metadata_format)+' -stack='+tostr(StackSize) + else + QLFlagsStr:='-b rawseg -q'; end; ExeName:=current_module.exefilename; @@ -292,18 +298,20 @@ begin Replace(cmdstr,'$STRIP',StripStr); Replace(cmdstr,'$GCSECTIONS',GCSectionsStr); Replace(cmdstr,'$DYNLINK',DynLinkStr); + Replace(cmdstr,'$QLFLAGS',QLFlagsStr); MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false); { Kludge: With the above linker script, vlink will produce two files. The main binary and the relocation info. Here we copy the two together. (KB) } - if MakeSinclairQLExe then + if MakeSinclairQLExe and not sinclairql_vlink_experimental then begin QLHeader:=DefaultQLHeader; XTccData:=DefaultXTccData; BinSize:=0; + RelocSize:=0; bufsize:=16384; {$push} {$i-} @@ -321,13 +329,18 @@ begin assign(fd,ExeName); rewrite(fd,1); + assign(fs,ExeName+'.'+ProgramHeaderName+'.rel'+ProgramHeaderName); + reset(fs,1); + RelocSize := FileSize(fs); + close(fs); + assign(fs,ExeName+'.'+ProgramHeaderName); reset(fs,1); BinSize := FileSize(fs); { We assume .bss size is total size indicated by linker minus emmited binary. DataSpace size is .bss + stack space } - DataSpace := NToBE(DWord(HeaderSize - BinSize + StackSize)); + DataSpace := NToBE(DWord(max((HeaderSize - BinSize) - RelocSize + StackSize,0))); { Option: prepend QEmuLator and QPC2 v5 compatible header to EXE } if sinclairql_metadata_format='QHDR' then -- cgit v1.2.1 From d7c24a635b8ec7dad69c558a863cf37033f52614 Mon Sep 17 00:00:00 2001 From: florian Date: Mon, 19 Apr 2021 19:54:39 +0000 Subject: * patch by J. Gareth Moreton: AArch64 OptPass1Shift register tracking fault fix, resolves #38691 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49235 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aarch64/aoptcpu.pas | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/compiler/aarch64/aoptcpu.pas b/compiler/aarch64/aoptcpu.pas index 4ef898284e..dc5e327cf2 100644 --- a/compiler/aarch64/aoptcpu.pas +++ b/compiler/aarch64/aoptcpu.pas @@ -379,15 +379,23 @@ Implementation taicpu(hp1).oper[0]^.reg, taicpu(p).oper[1]^.reg, shifterop); + { Make sure the register used in the shifting is tracked all + the way through, otherwise it may become deallocated while + it's still live and cause incorrect optimisations later } + if (taicpu(hp1).oper[0]^.reg <> taicpu(p).oper[1]^.reg) then + begin + TransferUsedRegs(TmpUsedRegs); + UpdateUsedRegs(TmpUsedRegs, tai(p.Next)); + ALlocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, TmpUsedRegs); + end; + taicpu(hp2).fileinfo:=taicpu(hp1).fileinfo; asml.insertbefore(hp2, hp1); - GetNextInstruction(p, hp2); - asml.remove(p); - asml.remove(hp1); - p.free; - hp1.free; - p:=hp2; - DebugMsg('Peephole FoldShiftProcess done', p); + + RemoveInstruction(hp1); + RemoveCurrentp(p); + + DebugMsg('Peephole FoldShiftProcess done', hp2); Result:=true; break; end; -- cgit v1.2.1 From d2e345b7a3c3badb5c57fb8ea6c5953381ab1284 Mon Sep 17 00:00:00 2001 From: jonas Date: Mon, 19 Apr 2021 20:52:12 +0000 Subject: * AArch64: fix storing a 32 bit value in the lower 32 bits of a 64 bit subsetreg (mantis #38766) git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49236 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aarch64/hlcgcpu.pas | 3 ++- tests/webtbs/tw38766.pp | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/webtbs/tw38766.pp diff --git a/compiler/aarch64/hlcgcpu.pas b/compiler/aarch64/hlcgcpu.pas index 593c202ef8..9de4e55ad7 100644 --- a/compiler/aarch64/hlcgcpu.pas +++ b/compiler/aarch64/hlcgcpu.pas @@ -210,7 +210,8 @@ implementation if slopt in [SL_SETZERO,SL_SETMAX] then inherited else if not(sreg.bitlen in [32,64]) or - (sreg.startbit<>0) then + (sreg.startbit<>0) or + (getsubreg(fromreg)y then + result:=x + else + result:=y; +end; + +function test: trec; inline; +begin + result.x:=1; + result.y:=2; + result.x:=max(result.x,result.y); +end; + +begin + if test.x<>2 then + halt(1); + if test.y<>2 then + halt(2); +end. -- cgit v1.2.1 From 66a646304774a3368b1e6442543f8ff3215db98a Mon Sep 17 00:00:00 2001 From: lacak Date: Tue, 20 Apr 2021 06:38:41 +0000 Subject: fcl-db: return default values for (published) properties where getters are not implemented yet. git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49238 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-db/src/base/fields.inc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/fcl-db/src/base/fields.inc b/packages/fcl-db/src/base/fields.inc index 9a94d9abed..262b331125 100644 --- a/packages/fcl-db/src/base/fields.inc +++ b/packages/fcl-db/src/base/fields.inc @@ -68,12 +68,13 @@ end; function TFieldDef.AddChild: TFieldDef; begin + // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.AddChild // Adds a new TFieldDef object to the ChildDefs array. end; function TFieldDef.GetChildDefs: TFieldDefs; begin - + Result:=nil; end; procedure TFieldDef.SetChildDefs(AValue: TFieldDefs); @@ -84,11 +85,13 @@ end; function TFieldDef.HasChildDefs: Boolean; begin // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.HasChildDefs + Result:=False; end; function TFieldDef.GetParentDef: TFieldDef; begin // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.ParentDef + Result:=nil; end; procedure TFieldDef.Assign(APersistent: TPersistent); @@ -3705,6 +3708,7 @@ end; function TObjectField.GetFieldCount: Integer; begin // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldCount + Result:=0; end; function TObjectField.GetFields: TFields; @@ -3716,6 +3720,7 @@ end; function TObjectField.GetFieldValue(AIndex: Integer): Variant; begin // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldValue + Result:=NULL; end; procedure TObjectField.SetFieldValue(AIndex: Integer; const AValue: Variant); @@ -3732,6 +3737,7 @@ end; function TObjectField.GetAsVariant: Variant; begin // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetAsVariant + Result:=NULL; end; procedure TObjectField.SetVarValue(const AValue: Variant); -- cgit v1.2.1 From 4813da5171f4d11b23f06093bb346af7514f4322 Mon Sep 17 00:00:00 2001 From: karoly Date: Tue, 20 Apr 2021 10:02:39 +0000 Subject: sinclairql: added an entirely stub (for now) sysutils unit. added a classes unit. enabled building the whole rtl git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49239 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/objpas/sysutils/filutilh.inc | 2 +- rtl/sinclairql/buildrtl.pp | 7 +- rtl/sinclairql/classes.pp | 50 ++++ rtl/sinclairql/sysutils.pp | 501 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 556 insertions(+), 4 deletions(-) create mode 100644 rtl/sinclairql/classes.pp create mode 100644 rtl/sinclairql/sysutils.pp diff --git a/rtl/objpas/sysutils/filutilh.inc b/rtl/objpas/sysutils/filutilh.inc index 8fef58596d..afe45a6666 100644 --- a/rtl/objpas/sysutils/filutilh.inc +++ b/rtl/objpas/sysutils/filutilh.inc @@ -17,7 +17,7 @@ Type // Some operating systems need FindHandle to be a Pointer -{$if defined(unix) or defined(msdos) or defined(hasamiga) or defined(atari) or defined(win16)} +{$if defined(unix) or defined(msdos) or defined(hasamiga) or defined(atari) or defined(win16) or defined(sinclairql)} {$define FINDHANDLE_IS_POINTER} {$endif} diff --git a/rtl/sinclairql/buildrtl.pp b/rtl/sinclairql/buildrtl.pp index ec7f7d0b48..36d1352544 100644 --- a/rtl/sinclairql/buildrtl.pp +++ b/rtl/sinclairql/buildrtl.pp @@ -4,11 +4,12 @@ unit buildrtl; uses si_prc, + sysutils, ctypes, strings, - rtlconsts, {sysconst,} {math,} {types,} - {typinfo,} sortbase, {fgl,} {classes,} - charset, {character,} {getopts,} + rtlconsts, sysconst, math, types, + typinfo, sortbase, fgl, classes, + charset, character, getopts, fpwidestring; implementation diff --git a/rtl/sinclairql/classes.pp b/rtl/sinclairql/classes.pp new file mode 100644 index 0000000000..ca7f60f810 --- /dev/null +++ b/rtl/sinclairql/classes.pp @@ -0,0 +1,50 @@ +{ + This file is part of the Free Component Library (FCL) + Copyright (c) 2021 by the Free Pascal development team + + Classes unit for the Sinclair QL + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{$mode objfpc} + +{ determine the type of the resource/form file } +{$define Win16Res} + +unit Classes; + +interface + +uses + sysutils, + rtlconsts, + types, + sortbase, +{$ifdef FPC_TESTGENERICS} + fgl, +{$endif} + typinfo; + +{$i classesh.inc} + + +implementation + +{ OS - independent class implementations are in /inc directory. } +{$i classes.inc} + + +initialization + CommonInit; + +finalization + CommonCleanup; + +end. diff --git a/rtl/sinclairql/sysutils.pp b/rtl/sinclairql/sysutils.pp new file mode 100644 index 0000000000..bd45660a8b --- /dev/null +++ b/rtl/sinclairql/sysutils.pp @@ -0,0 +1,501 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2021 by Free Pascal development team + + Sysutils unit for Sinclair QL + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit sysutils; + +interface + +{$MODE objfpc} +{$MODESWITCH OUT} +{ force ansistrings } +{$H+} +{$modeswitch typehelpers} +{$modeswitch advancedrecords} + +{$DEFINE OS_FILESETDATEBYNAME} +{$DEFINE HAS_SLEEP} +{$DEFINE HAS_OSERROR} + +{OS has only 1 byte version for ExecuteProcess} +{$define executeprocuni} + +{ used OS file system APIs use ansistring } +{$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL} +{ OS has an ansistring/single byte environment variable API } +{$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL} + +{ Include platform independent interface part } +{$i sysutilh.inc} + +{ Platform dependent calls } + + +implementation + +uses + sysconst; + +{$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *) +{$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *) + +{ Include platform independent implementation part } +{$i sysutils.inc} + +{$i qdosfuncs.inc} +{$i smsfuncs.inc} + +{**************************************************************************** + File Functions +****************************************************************************} +{$I-}{ Required for correct usage of these routines } + + +(****** non portable routines ******) + +function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle; +begin + FileOpen:=-1; + if FileOpen < -1 then + FileOpen:=-1; +end; + + +function FileGetDate(Handle: THandle) : Int64; +begin + result:=-1; +end; + + +function FileSetDate(Handle: THandle; Age: Int64) : LongInt; +begin + result:=0; +end; + + +function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt; +var + f: THandle; +begin + result:=-1; + f:=FileOpen(FileName,fmOpenReadWrite); + if f < 0 then + exit; + result:=FileSetDate(f,Age); + FileClose(f); +end; + + +function FileCreate(const FileName: RawByteString) : THandle; +begin + FileCreate:=-1; + if FileCreate < -1 then + FileCreate:=-1; +end; + +function FileCreate(const FileName: RawByteString; Rights: integer): THandle; +begin + { Rights don't exist on the QL, so we simply map this to FileCreate() } + FileCreate:=FileCreate(FileName); +end; + +function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle; +begin + { Rights and ShareMode don't exist on the QL so we simply map this to FileCreate() } + FileCreate:=FileCreate(FileName); +end; + + +function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt; +begin + FileRead:=-1; + if (Count<=0) then + exit; + + FileRead:=-1; + if FileRead < -1 then + FileRead:=-1; +end; + + +function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt; +begin + FileWrite:=-1; + if (Count<=0) then + exit; + + FileWrite:=-1; + if FileWrite < -1 then + FileWrite:=-1; +end; + + +function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt; +var + dosResult: longint; +begin + FileSeek:=-1; + + dosResult:=-1; + if dosResult < 0 then + exit; + + FileSeek:=dosResult; +end; + +function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64; +begin + FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin); +end; + + +procedure FileClose(Handle: THandle); +begin +end; + + +function FileTruncate(Handle: THandle; Size: Int64): Boolean; +begin + FileTruncate:=False; +end; + + +function DeleteFile(const FileName: RawByteString) : Boolean; +begin + DeleteFile:=false; +end; + + +function RenameFile(const OldName, NewName: RawByteString): Boolean; +begin + RenameFile:=false; +end; + + + +(****** end of non portable routines ******) + + +function FileAge (const FileName : RawByteString): Int64; +var + f: THandle; +begin + FileAge:=-1; + f:=FileOpen(FileName,fmOpenRead); + if f < 0 then + exit; + FileAge:=FileGetDate(f); + FileClose(f); +end; + + +function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean; +begin + Result := False; +end; + + +function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean; +var + Attr: longint; +begin + FileExists:=false; + Attr:=FileGetAttr(FileName); + if Attr < 0 then + exit; + + result:=(Attr and (faVolumeID or faDirectory)) = 0; +end; + + +type + PInternalFindData = ^TInternalFindData; + TInternalFindData = record + dummy: pointer; + end; + + +Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint; +var + dosResult: longint; + IFD: PInternalFindData; +begin + result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. } + + new(IFD); + IFD^.dummy:=nil; + + Rslt.FindHandle:=nil; + dosResult:=-1; { add findfirst here } + if dosResult < 0 then + begin + InternalFindClose(IFD); + exit; + end; + + Rslt.FindHandle:=IFD; + + Name:=''; + SetCodePage(Name,DefaultFileSystemCodePage,false); + + Rslt.Time:=0; + Rslt.Size:=0; + + { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) } + Rslt.Attr := 128 or 0; + + result:=0; +end; + + +Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint; +var + dosResult: longint; + IFD: PInternalFindData; +begin + result:=-1; + IFD:=PInternalFindData(Rslt.FindHandle); + if not assigned(IFD) then + exit; + + dosResult:=-1; + if dosResult < 0 then + exit; + + Name:=''; + SetCodePage(Name,DefaultFileSystemCodePage,false); + + Rslt.Time:=0; + Rslt.Size:=0; + + { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) } + Rslt.Attr := 128 or 0; + + result:=0; +end; + + +Procedure InternalFindClose(var Handle: Pointer); +var + IFD: PInternalFindData; +begin + IFD:=PInternalFindData(Handle); + if not assigned(IFD) then + exit; + + dispose(IFD); +end; + + +(****** end of non portable routines ******) + +Function FileGetAttr (Const FileName : RawByteString) : Longint; +begin + FileGetAttr:=0; +end; + + +Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint; +begin + FileSetAttr:=-1; + + if FileSetAttr < -1 then + FileSetAttr:=-1 + else + FileSetAttr:=0; +end; + + + +{**************************************************************************** + Disk Functions +****************************************************************************} + +function DiskSize(Drive: Byte): Int64; +var + dosResult: longint; +begin + DiskSize := -1; + + dosResult:=-1; + if dosResult < 0 then + exit; + + DiskSize:=0; +end; + +function DiskFree(Drive: Byte): Int64; +var + dosResult: longint; +begin + DiskFree := -1; + + dosResult:=-1; + if dosResult < 0 then + exit; + + DiskFree:=0; +end; + +function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean; +var + Attr: longint; +begin + DirectoryExists:=false; + Attr:=FileGetAttr(Directory); + if Attr < 0 then + exit; + + result:=(Attr and faDirectory) <> 0; +end; + + + +{**************************************************************************** + Locale Functions +****************************************************************************} + +Procedure GetLocalTime(var SystemTime: TSystemTime); +begin + DateTimeToSystemTime(FileDateToDateTime(0),SystemTime); +end; + + +Procedure InitAnsi; +Var + i : longint; +begin + { Fill table entries 0 to 127 } + for i := 0 to 96 do + UpperCaseTable[i] := chr(i); + for i := 97 to 122 do + UpperCaseTable[i] := chr(i - 32); + for i := 123 to 191 do + UpperCaseTable[i] := chr(i); + Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT)); + + for i := 0 to 64 do + LowerCaseTable[i] := chr(i); + for i := 65 to 90 do + LowerCaseTable[i] := chr(i + 32); + for i := 91 to 191 do + LowerCaseTable[i] := chr(i); + Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT)); +end; + + +Procedure InitInternational; +begin + InitInternationalGeneric; + InitAnsi; +end; + +function SysErrorMessage(ErrorCode: Integer): String; +begin + Result:=Format(SUnknownErrorCode,[ErrorCode]); +end; + +function GetLastOSError: Integer; +begin + result:=-1; +end; + +{**************************************************************************** + OS utility functions +****************************************************************************} + +function GetPathString: String; +begin + {writeln('Unimplemented GetPathString');} + result := ''; +end; + +Function GetEnvironmentVariable(Const EnvVar : String) : String; +begin + {writeln('Unimplemented GetEnvironmentVariable');} + result:=''; +end; + +Function GetEnvironmentVariableCount : Integer; +begin + {writeln('Unimplemented GetEnvironmentVariableCount');} + result:=0; +end; + +Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif}; +begin + {writeln('Unimplemented GetEnvironmentString');} + result:=''; +end; + +function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]): + integer; +var + tmpPath: RawByteString; + pcmdline: ShortString; + CommandLine: RawByteString; + E: EOSError; +begin + tmpPath:=ToSingleByteFileSystemEncodedFileName(Path); + pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine); + + result:=-1; { execute here } + + if result < 0 then begin + if ComLine = '' then + CommandLine := Path + else + CommandLine := Path + ' ' + ComLine; + + E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]); + E.ErrorCode := result; + raise E; + end; +end; + +function ExecuteProcess (const Path: RawByteString; + const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer; +var + CommandLine: RawByteString; + I: integer; + +begin + Commandline := ''; + for I := 0 to High (ComLine) do + if Pos (' ', ComLine [I]) <> 0 then + CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"' + else + CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]); + ExecuteProcess := ExecuteProcess (Path, CommandLine); +end; + +procedure Sleep(Milliseconds: cardinal); +begin + {writeln('Unimplemented sleep');} +end; + + +{**************************************************************************** + Initialization code +****************************************************************************} + +Initialization + InitExceptions; + InitInternational; { Initialize internationalization settings } + OnBeep:=Nil; { No SysBeep() on the QL for now. } + +Finalization + FreeTerminateProcs; + DoneExceptions; +end. -- cgit v1.2.1 From 73ebe6abbe99cd7518f8dd5b9ec1106357ae8f88 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 20 Apr 2021 11:39:30 +0000 Subject: * Mustache templates implementation git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49240 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-mustache/examples/README.txt | 27 + packages/fcl-mustache/examples/demo1.lpi | 57 + packages/fcl-mustache/examples/demo1.lpr | 42 + packages/fcl-mustache/examples/demo2.lpi | 57 + packages/fcl-mustache/examples/demo2.lpr | 48 + packages/fcl-mustache/examples/family.csv | 7 + packages/fcl-mustache/examples/family.json | 10 + packages/fcl-mustache/examples/family.tmpl | 22 + packages/fcl-mustache/examples/mustache.lpi | 57 + packages/fcl-mustache/examples/mustache.lpr | 207 +++ packages/fcl-mustache/src/fpdbmustache.pp | 268 ++++ packages/fcl-mustache/src/fpexmustache.pp | 399 ++++++ packages/fcl-mustache/src/fpmustache.pp | 1340 ++++++++++++++++++++ packages/fcl-mustache/tests/spec/comments.json | 1 + packages/fcl-mustache/tests/spec/delimiters.json | 1 + .../fcl-mustache/tests/spec/interpolation.json | 1 + packages/fcl-mustache/tests/spec/inverted.json | 1 + packages/fcl-mustache/tests/spec/partials.json | 1 + packages/fcl-mustache/tests/spec/sections.json | 1 + packages/fcl-mustache/tests/tcbasemustache.pas | 290 +++++ packages/fcl-mustache/tests/tcdbmustache.pas | 149 +++ packages/fcl-mustache/tests/tcexmustache.pas | 199 +++ packages/fcl-mustache/tests/tcmustache.pas | 728 +++++++++++ packages/fcl-mustache/tests/tcspecs.pas | 188 +++ packages/fcl-mustache/tests/testmustache.lpi | 88 ++ packages/fcl-mustache/tests/testmustache.lpr | 29 + packages/fpmake_add.inc | 1 + packages/fpmake_proc.inc | 6 + 28 files changed, 4225 insertions(+) create mode 100644 packages/fcl-mustache/examples/README.txt create mode 100644 packages/fcl-mustache/examples/demo1.lpi create mode 100644 packages/fcl-mustache/examples/demo1.lpr create mode 100644 packages/fcl-mustache/examples/demo2.lpi create mode 100644 packages/fcl-mustache/examples/demo2.lpr create mode 100644 packages/fcl-mustache/examples/family.csv create mode 100644 packages/fcl-mustache/examples/family.json create mode 100644 packages/fcl-mustache/examples/family.tmpl create mode 100644 packages/fcl-mustache/examples/mustache.lpi create mode 100644 packages/fcl-mustache/examples/mustache.lpr create mode 100644 packages/fcl-mustache/src/fpdbmustache.pp create mode 100644 packages/fcl-mustache/src/fpexmustache.pp create mode 100644 packages/fcl-mustache/src/fpmustache.pp create mode 100644 packages/fcl-mustache/tests/spec/comments.json create mode 100644 packages/fcl-mustache/tests/spec/delimiters.json create mode 100644 packages/fcl-mustache/tests/spec/interpolation.json create mode 100644 packages/fcl-mustache/tests/spec/inverted.json create mode 100644 packages/fcl-mustache/tests/spec/partials.json create mode 100644 packages/fcl-mustache/tests/spec/sections.json create mode 100644 packages/fcl-mustache/tests/tcbasemustache.pas create mode 100644 packages/fcl-mustache/tests/tcdbmustache.pas create mode 100644 packages/fcl-mustache/tests/tcexmustache.pas create mode 100644 packages/fcl-mustache/tests/tcmustache.pas create mode 100644 packages/fcl-mustache/tests/tcspecs.pas create mode 100644 packages/fcl-mustache/tests/testmustache.lpi create mode 100644 packages/fcl-mustache/tests/testmustache.lpr diff --git a/packages/fcl-mustache/examples/README.txt b/packages/fcl-mustache/examples/README.txt new file mode 100644 index 0000000000..b46598b216 --- /dev/null +++ b/packages/fcl-mustache/examples/README.txt @@ -0,0 +1,27 @@ +demo1 sample program: + +Demonstrates the most basic use of the mustache parser + +demo2 sample program: + +Demonstrates the use of the mustache parser with a CSV dataset + + +mustache example program: + +Can be used to load a template and data, and process the result. +Output to standard output or file. +The template and JSON value can be loaded from file (using @filename), +or their value can be specified directly on the command-line. + +Example usage: + +Load template from family.tmpl file, data from family.json file: + +./mustache -d title="my family" -t @family.tmpl -j @family.json + +Load template from family.tmpl file, data from family.csv file: + +./mustache -d title="my family" -t @family.tmpl -c family.csv + +Use of expressions can be enabled with the -e switch. diff --git a/packages/fcl-mustache/examples/demo1.lpi b/packages/fcl-mustache/examples/demo1.lpi new file mode 100644 index 0000000000..6e03c0c1fd --- /dev/null +++ b/packages/fcl-mustache/examples/demo1.lpi @@ -0,0 +1,57 @@ + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <Units> + <Unit> + <Filename Value="demo1.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="demo1"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../src"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/packages/fcl-mustache/examples/demo1.lpr b/packages/fcl-mustache/examples/demo1.lpr new file mode 100644 index 0000000000..652ec7057c --- /dev/null +++ b/packages/fcl-mustache/examples/demo1.lpr @@ -0,0 +1,42 @@ +{ Demo for mustache engine with JSON context + + Copyright (C) 2021 michael Van Canneyt michael@freepascal.org + + 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. +} +program demo1; + +// jsonparser includes the json parser. + +uses jsonparser, fpmustache; + +Const + JSON = '{ "products" : [ {"name" : "BMW" }, {"name" : "Mercedes"}, { "name" : "Audi" }] }'; + + // Mock markdown table + Template = + '| name |'+sLineBreak+ + '|------|'+sLineBreak+ + '{{#products}}| {{name}} |'+sLineBreak+ + '{{/products}}'; + +Var + M : TMustache; + +begin + M:=TMustache.Create(Nil); + try + // Json support enabled by default + Writeln(M.Render(Template,JSON)); + finally + M.Free; + end; +end. + diff --git a/packages/fcl-mustache/examples/demo2.lpi b/packages/fcl-mustache/examples/demo2.lpi new file mode 100644 index 0000000000..dd4e245773 --- /dev/null +++ b/packages/fcl-mustache/examples/demo2.lpi @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="12"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <Title Value="demo2"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <Units> + <Unit> + <Filename Value="demo2.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="demo2"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../src"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/packages/fcl-mustache/examples/demo2.lpr b/packages/fcl-mustache/examples/demo2.lpr new file mode 100644 index 0000000000..4b5b20f885 --- /dev/null +++ b/packages/fcl-mustache/examples/demo2.lpr @@ -0,0 +1,48 @@ +{ Demo for mustache engine with database context + + Copyright (C) 2021 michael Van Canneyt michael@freepascal.org + + 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. +} + +program demo2; + +uses csvdataset, fpmustache, fpdbmustache; + +Const + // Mock markdown table + Template = + '| name | age | '+sLineBreak+ + '|------|------|'+sLineBreak+ + '{{#family}}| {{name}} | {{age}} |'+sLineBreak+ + '{{/family}}'; + +Var + M : TMustache; + C : TMustacheDBContext; + D : TCSVDataset; + +begin + M:=TMustache.Create(Nil); + try + D:=TCSVDataset.Create(Nil); + D.CSVOptions.FirstLineAsFieldNames:=True; + D.LoadFromFile('family.csv'); + C:=TMustacheDBContext.Create(Nil); + C.AddDataset(D,'family'); + M.Template:=Template; + Writeln(M.Render(C)); + finally + M.Free; + D.Free; + C.Free; + end; +end. + diff --git a/packages/fcl-mustache/examples/family.csv b/packages/fcl-mustache/examples/family.csv new file mode 100644 index 0000000000..628dc27a08 --- /dev/null +++ b/packages/fcl-mustache/examples/family.csv @@ -0,0 +1,7 @@ +name,age +Father,30 +Mother,29 +Grandfather,62 +GrandMother,61 +Child 1,2 +Child 2,4 diff --git a/packages/fcl-mustache/examples/family.json b/packages/fcl-mustache/examples/family.json new file mode 100644 index 0000000000..39475e98d1 --- /dev/null +++ b/packages/fcl-mustache/examples/family.json @@ -0,0 +1,10 @@ +{ + "data" : [ + { "name" : "Father", "age": 30 }, + { "name" : "Mother", "age": 29 }, + { "name" : "Grandfather", "age": 62 }, + { "name" : "GrandMother", "age": 61 }, + { "name" : "Child 1", "age": 2 }, + { "name" : "Child 2", "age": 4 } + ] +} \ No newline at end of file diff --git a/packages/fcl-mustache/examples/family.tmpl b/packages/fcl-mustache/examples/family.tmpl new file mode 100644 index 0000000000..b6174cfcfe --- /dev/null +++ b/packages/fcl-mustache/examples/family.tmpl @@ -0,0 +1,22 @@ +<html> + <head> + <title>{{title}} + + +

Family members

+ + + + + + + +{{#data}} + + + +{{/data}} + +
NameAge
{{name}}{{age}}
+ + diff --git a/packages/fcl-mustache/examples/mustache.lpi b/packages/fcl-mustache/examples/mustache.lpi new file mode 100644 index 0000000000..24c058f4a4 --- /dev/null +++ b/packages/fcl-mustache/examples/mustache.lpi @@ -0,0 +1,57 @@ + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <Units> + <Unit> + <Filename Value="mustache.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="mustache"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../src"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/packages/fcl-mustache/examples/mustache.lpr b/packages/fcl-mustache/examples/mustache.lpr new file mode 100644 index 0000000000..7a48df1dad --- /dev/null +++ b/packages/fcl-mustache/examples/mustache.lpr @@ -0,0 +1,207 @@ +program mustache; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX} + cthreads, + {$ENDIF} + Classes, SysUtils, CustApp, strutils, fpjson, jsonparser, csvdataset, fpMustache, fpexmustache, fpdbmustache, iostream; + +type + + { TMustacheApplication } + + TMustacheApplication = class(TCustomApplication) + private + FTemplate : TMustacheString; + FJSON : TJSONStringType; + FCSV: TCSVDataset; + FPartials, + FDefines : TStrings; + FAllowExpressions : Boolean; + Foutput, + FSection, + FRootPath : String; + procedure DoGetDefine(const aName: TMustacheString; var aHandled: Boolean; + var aValue: TMustacheString); + procedure ProcessOptions; + Procedure Createoutput; + procedure Usage(ErrorMsg: String); + protected + procedure DoRun; override; + + public + constructor Create(TheOwner: TComponent); override; + destructor Destroy; override; + end; + +{ TMustacheApplication } + +procedure TMustacheApplication.Usage(ErrorMsg : String); + +begin + If ErrorMsg<>'' then + Writeln('Error : ',ErrorMsg); + Writeln('Usage : mustache [options]'); + Writeln('Where options is one or more of:'); + writeln('-c --csv=FILE Use a CSV file as data source. First line must contain column names.'); + writeln('-d --define=name=value Define fixed value.'); + writeln('-e --expressions Allow expressions.'); + writeln('-h --help This message.'); + writeln('-j --json=JSON Use JSON as data source. @FILENAME will read JSON from file (UTF8).'); + writeln('-o --output=FILE output file to write output to. If empty, stdout is assumed.'); + writeln('-p --partial=name=PARTIAL Register partial. @FILENAME reads partial from file.'); + writeln('-r --root=PATH Register variables at root path PATH for expression engine'); + writeln('-s --section=SECTIOn Section name for CSV data'); + writeln('-t --template=TEMPLATE Use TEMPLATE as data source. @FILENAME will read template from file (UTF8). Required.'); + Halt(Ord(ErrorMsg<>'')); +end; + +procedure TMustacheApplication.ProcessOptions; + + Function StringOrFile(S : String) : UTF8String; + + begin + if Copy(S,1,1)<>'@' then + Result:=S + else + With TFileStream.Create(Copy(S,2,Length(S)-1),fmOpenRead or fmShareDenyNone) do + try + SetLength(Result,Size); + ReadBuffer(Result[1],Size); + finally + Free; + end; + end; + +Var + S : String; + +begin + if Not HasOption('t','template') then + Raise Exception.Create('Need a template'); + if HasOption('c','csv') and HasOption('j','json') then + Raise Exception.Create('Cannot specify both JSON or CSV'); + FTemplate:=StringOrFile(GetOptionValue('t','template')); + if HasOption('j','json') then + FJSON:=StringOrFile(GetOptionValue('j','json')) + else if HasOption('c','csv') then + begin + FCSV:=TCSVDataset.Create(Self); + FCSV.FileName:=GetOptionValue('c','csv'); + FCSV.CSVOptions.FirstLineAsFieldNames:=True; + FCSV.Open; + end; + for S in GetOptionValues('d','define') do + FDefines.Add(S); + for S in GetOptionValues('p','partial') do + FPartials.Add(ExtractWord(1,S,['='])+'='+StringOrFile(ExtractWord(2,S,['=']))); + FAllowExpressions:=HasOption('e','expressions'); + FRootPath:=GetOptionValue('r','root'); + FSection:=GetOptionValue('s','section'); + if FSection='' then + FSection:='data'; + Foutput:=GetOptionValue('o','output'); +end; + +procedure TMustacheApplication.DoGetDefine(const aName: TMustacheString; + var aHandled: Boolean; var aValue: TMustacheString); + +Var + Idx : Integer; + +begin + Writeln('Getting define ',aName); + Idx:=FDefines.IndexOfName(aName); + aHandled:=Idx<>-1; + if aHandled then + aValue:=FDefines.ValueFromIndex[Idx] + else + aValue:=''; +end; + +procedure TMustacheApplication.DoRun; +var + ErrorMsg: String; +begin + Terminate; + // quick check parameters + ErrorMsg:=CheckOptions('het:j:c:d:o:r:', ['help','template','json','csv','define','output','expressions','root']); + if (ErrorMsg<>'') or HasOption('h','help') then + Usage(ErrorMsg); + ProcessOptions; + CreateOutput; +end; + +procedure TMustacheApplication.CreateOutput; + +Var + M : TMustache; + C : TMustacheContext; + O : TStream; + S : TMustacheString; + +begin + O:=Nil; + M:=Nil; + C:=Nil; + try + if FAllowExpressions then + M:=TMustache.Create(Self) + else + begin + M:=TMustacheExpr.Create(Self); + if (FRootPath<>'') and (FJSON<>'') then + TMustacheExpr(M).RegisterVariables(FJSON,FRootPath,True); + end; + M.Partials:=FPartials; + if Assigned(FCSV) then + begin + C:=TMustacheDBContext.Create(@DoGetDefine); + TMustacheDBContext(C).AddDataset(FCSV,FSection); + end + else if (FJSON<>'') then + C:=TMustacheJSONContext.Create(GetJSON(FJSON),@DoGetDefine) + else + C:=TMustacheContext.Create(@DoGetDefine); + if Foutput<>'' then + O:=TFileStream.Create(Foutput,fmCreate) + else + O:=TIOStream.Create(iosOutput); + M.Template:=FTemplate; + S:=M.Render(C); + O.WriteBuffer(S[1],Length(S)); + finally + O.Free; + C.Free; + M.Free; + end; +end; + +constructor TMustacheApplication.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + FPartials:=TStringList.Create; + FDefines:=TStringList.Create; + StopOnException:=True; +end; + +destructor TMustacheApplication.Destroy; +begin + FreeAndNil(FPartials); + FreeAndNil(FDefines); + FreeAndNil(FCSV); + inherited Destroy; +end; + + +var + Application: TMustacheApplication; +begin + Application:=TMustacheApplication.Create(nil); + Application.Title:='Mustache Templater'; + Application.Run; + Application.Free; +end. + diff --git a/packages/fcl-mustache/src/fpdbmustache.pp b/packages/fcl-mustache/src/fpdbmustache.pp new file mode 100644 index 0000000000..0f7d6d72d9 --- /dev/null +++ b/packages/fcl-mustache/src/fpdbmustache.pp @@ -0,0 +1,268 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + This file contains a Mustache DB context, getting data from a dataset + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit fpdbmustache; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, db, fpMustache; + +Type + + { TDatasetCollectionItem } + + TDatasetCollectionItem = Class(TCollectionItem) + private + FDataset: TDataSet; + FSection: String; + Public + Property Dataset : TDataSet Read FDataset Write FDataset; + Property SectionName : String Read FSection Write FSection; + end; + + TDatasetCollection = Class(TCollection) + private + function GetDS(aIndex : Integer): TDatasetCollectionItem; + Public + Function IndexOfDataset(aDataset : TDataset) : Integer; + Function IndexOfSection(aSection : String) : Integer; + Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDS; default; + end; + + { TMustacheDBContext } + + TMustacheDBContext = Class(TMustacheContext) + Private + Type + TPair = Record + atStart : Boolean; + Value : TDataset; + end; + Private + FStack : Array of TPair; + FCount : Integer; + FStaticValues: TStrings; + FDatasets : TDatasetCollection; + Function FindField(Const aName : TMustacheString) : TField; + function GetDataset(aIndex : Integer): TDatasetCollectionItem; + function GetDatasetCount: INteger; + procedure SetStaticValues(AValue: TStrings); + Public + Constructor Create(aCallback : TGetTextValueEvent); override; + Destructor destroy; override; + Procedure Clear; + Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override; + Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override; + Procedure PopSection(Const aName : TMustacheString); override; + Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override; + Procedure AddDataset(aDataset : TDataset; aSectionName : String = ''); + Procedure RemoveDataset(aDataset : TDataset); + Property StaticValues : TStrings Read FStaticValues Write SetStaticValues; + Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDataset; + Property DatasetCount : INteger Read GetDatasetCount; + end; + +implementation + +uses StrUtils; + +Resourcestring + SErrPopSectionNoPush = 'PopSection %s without push'; + SErrDatasetNameEmpty = 'Dataset name and section cannot both be empty'; + SErrDatasetEmpty = 'Dataset is Nil'; + SErrDuplicateDataSetName = 'Duplicate dataset name: %s'; + +{ TMustacheDBContext } + +function TMustacheDBContext.FindField(const aName: TMustacheString): TField; + +Var + aCount : Integer; + +begin + Result:=Nil; + aCount:=FCount-1; + While (Result=Nil) and (aCount>=0) do + begin + Result:=FStack[aCount].Value.FieldByName(aName); + Dec(aCount); + end; +end; + +function TMustacheDBContext.GetDataset(aIndex : Integer + ): TDatasetCollectionItem; +begin + Result:=FDatasets[aIndex]; +end; + +function TMustacheDBContext.GetDatasetCount: INteger; +begin + Result:=FDatasets.Count; +end; + +procedure TMustacheDBContext.SetStaticValues(AValue: TStrings); +begin + if FStaticValues=AValue then Exit; + FStaticValues.Assign(AValue); +end; + +constructor TMustacheDBContext.Create(aCallback: TGetTextValueEvent); +begin + inherited Create(aCallback); + FDatasets:=TDatasetCollection.Create(TDatasetCollectionItem); + FStaticValues:=TStringList.Create; + SetLength(FStack,JSONListGrowCount); + FCount:=0; +end; + +destructor TMustacheDBContext.destroy; +begin + FreeAndNil(FStaticValues); + FreeAndNil(FDatasets); + inherited destroy; +end; + +procedure TMustacheDBContext.Clear; +begin + FStaticValues.Clear; + FDatasets.Clear; +end; + +function TMustacheDBContext.MoveNextSectionItem(const aName: TMustacheString + ): Boolean; +begin + if FStack[FCount-1].atStart then + FStack[FCount-1].atStart:=False + else + FStack[FCount-1].Value.Next; + Result:=Not FStack[FCount-1].Value.EOF; +end; + +function TMustacheDBContext.PushSection(const aName: TMustacheString + ): TMustacheSectionType; + +Var + aDS : TDataset; + Idx : Integer; +begin + Result:=mstNone; + Idx:=FDatasets.IndexOfSection(aName); + if Idx=-1 then + Exit; + aDS:=FDatasets[Idx].Dataset; + if aDS.IsEmpty then + exit; + if FCount=Length(FStack) then + SetLength(FStack,FCount+JSONListGrowCount); + FStack[FCount].Value:=aDS; + FStack[FCount].atStart:=True; + Inc(FCount,1); + Result:=mstList; +end; + +procedure TMustacheDBContext.PopSection(const aName: TMustacheString); +begin + if FCount<1 then + Raise EMustache.CreateFmt(SErrPopSectionNoPush,[aName]); + Dec(FCount,1); +end; + +function TMustacheDBContext.GetTextValue(const aName: TMustacheString + ): TMustacheString; + +Var + F : TField; + idx : Integer; + +begin + F:=Nil; + if Pos('.',aName)=0 then + F:=FindField(aName) + else if WordCount(aName,['.'])=2 then + begin + Idx:=FDatasets.IndexOfSection(ExtractWord(1,aName,['.'])); + if (Idx<>-1) then + F:=FDatasets[Idx].Dataset.FindField(ExtractWord(2,aName,['.'])); + end; + If Assigned(F) then + Result:=F.AsString + else + begin + Idx:=FStaticValues.IndexOfName(aName); + if Idx<>-1 then + Result:=FStaticValues.ValueFromIndex[Idx] + else + Result:=Inherited GetTextValue(aName); + end; +end; + +procedure TMustacheDBContext.AddDataset(aDataset: TDataset; aSectionName: String); + +Var + DCI : TDatasetCollectionItem; + aName : String; + +begin + aName:=aSectionName; + if aName='' then + aName:=aDataset.Name; + if aName='' then + raise EMustache.Create(SErrDatasetNameEmpty); + if aDataset=Nil then + raise EMustache.Create(SErrDatasetEmpty); + if FDatasets.IndexOfSection(aName)<>-1 then + raise EMustache.CreateFmt(SErrDuplicateDataSetName, [aName]); + DCI:=FDatasets.Add as TDatasetCollectionItem; + DCI.Dataset:=aDataset; + DCI.SectionName:=aName; +end; + +procedure TMustacheDBContext.RemoveDataset(aDataset: TDataset); + +Var + Idx : Integer; + +begin + Idx:=FDatasets.IndexOfDataset(aDataset); + if Idx<>-1 then + FDatasets.Delete(Idx); +end; + +{ TDatasetCollection } + +function TDatasetCollection.GetDS(aIndex : Integer): TDatasetCollectionItem; +begin + Result:=Items[aIndex] as TDatasetCollectionItem; +end; + +function TDatasetCollection.IndexOfDataset(aDataset: TDataset): Integer; +begin + Result:=Count-1; + While (Result>=0) and (GetDS(Result).Dataset<>ADataset) do + Dec(Result); +end; + +function TDatasetCollection.IndexOfSection(aSection: String): Integer; +begin + Result:=Count-1; + While (Result>=0) and not SameText(GetDS(Result).SectionName,ASection) do + Dec(Result); +end; + +end. + diff --git a/packages/fcl-mustache/src/fpexmustache.pp b/packages/fcl-mustache/src/fpexmustache.pp new file mode 100644 index 0000000000..6191e6bd78 --- /dev/null +++ b/packages/fcl-mustache/src/fpexmustache.pp @@ -0,0 +1,399 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + This file contains a Mustache descendent with FPExpr parser expression support + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit fpexmustache; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, fpexprpars, fpmustache, fpjson; + +Type + + { TMustacheExprElement } + + TMustacheExprElement = Class(TMustacheElement) + private + FNode: TFPExprNode; + FExpr : TMustacheString; + Protected + Procedure SetNode(aNode : TFPExprNode); virtual; + Function GetData : TMustacheString;override; + Procedure SetData(const aValue : TMustacheString) ; override; + Public + Destructor Destroy; override; + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + Property Node : TFPExprNode Read FNode; + end; + + { TMustacheExprParser } + + TMustacheExprParser = class(TMustacheParser) + private + FExprEnd: Char; + FExprParser: TFPExpressionParser; + FExprStart: Char; + Protected + function CreateDefault(aParent: TMustacheElement; aPosition: Integer; const aName: String): TMustacheElement; override; + Public + Constructor Create(aTemplate : TMustacheString = '';aStart: TMustacheString='';aStop: TMustacheString = ''); override; + // Default [ + Property ExprStart : Char Read FExprStart Write FExprStart; + // Default ] + Property ExprEnd : Char Read FExprEnd Write FExprEnd; + // Our instance + Property ExprParser : TFPExpressionParser Read FExprParser Write FExprParser; + end; + + { TMustacheExpr } + + TMustacheExpr = Class(TMustache) + private + FExprEndChar: String; + FExpressionParser: TFPExpressionParser; + FExprStartChar: String; + FCurrentContext : TMustacheContext; + function GetResultType(aValue: TJSONData): TResultType; + procedure SetExprEndChar(AValue: String); + procedure SetExpressionParser(AValue: TFPExpressionParser); + procedure SetExprStartChar(AValue: String); + function DoGetExpressionParser : TFPExpressionParser; + Protected + procedure DoGetVariable(var Result: TFPExpressionResult; ConstRef AName: ShortString); virtual; + Procedure Notification(AComponent: TComponent; Operation: TOperation); override; + Function CreateParser(aTemplate: TMustacheString): TMustacheParser; override; + function GetExpressionParser(aOwner : TComponent): TFPExpressionParser; virtual; + Public + Constructor Create(aOwner : TComponent); override; + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput); override; overload; + // Register variables from JSON in the expression engine. + // If UseEvent is true, the variables will be retrieved while parsing with an event. + // If UseEvent is false, the variables will be registered as static values. + Procedure RegisterVariables (aContext : TMustacheJSONContext; aPath : TJSONStringType = ''; UseEvent : Boolean = True); + Procedure RegisterVariables (aJSON : String; aPath : TJSONStringType = ''; UseEvent : Boolean = True); + Procedure RegisterVariables (aJSON : TJSONObject; aPath : TJSONStringType = ''; UseEvent : Boolean = True); + Published + // Default [ + Property ExprStartChar : String Read FExprStartChar Write SetExprStartChar; + // Default ] + Property ExprEndChar : String Read FExprEndChar Write SetExprEndChar; + // An expression parser instance. If none is specified, then a default is created. + Property ExpressionParser : TFPExpressionParser Read DoGetExpressionParser Write SetExpressionParser; + end; + + { TMustacheExpressionParser } + + TMustacheExpressionParser = class(TFPExpressionParser) + end; + +implementation + +uses sysutils; + +Resourcestring + SErrLengthStartMustBe1 = 'Length expression start delimiter must be 1'; + SErrLengthEndMustBe1 = 'Length expression end delimiter must be 1'; + +{ TMustacheExprElement } + +procedure TMustacheExprElement.SetNode(aNode: TFPExprNode); +begin + FNode:=aNode; +end; + +function TMustacheExprElement.GetData: TMustacheString; +begin + Result:=FExpr; +end; + +procedure TMustacheExprElement.SetData(const aValue: TMustacheString); +begin + FExpr:=aValue; +end; + +procedure TMustacheExprElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix: String; aLast: Boolean); + +Var + Res : TFPExpressionResult; + S : TMustacheString; + +begin + Res:=Node.NodeValue; + case Res.ResultType of + rtString : S:=Res.ResString; + rtBoolean : S:=BoolToStr(Res.ResBoolean,True); + rtInteger : S:=IntToStr(Res.ResInteger); + rtFloat : S:=FormatFloat('0.0#######',Res.ResFloat); + rtCurrency : S:=CurrToStr(Res.ResCurrency); + rtDateTime : S:=DateTimeToStr(Res.ResDateTime); + end; + aOutput.Output(aPrefix+S); +end; + +destructor TMustacheExprElement.Destroy; +begin + FreeAndNil(FNode); + inherited Destroy; +end; + +{ TMustacheExprParser } + +function TMustacheExprParser.CreateDefault(aParent: TMustacheElement; + aPosition: Integer; const aName: String): TMustacheElement; + +Var + L : Integer; + N : TFPExprNode; + +begin + N:=Nil; + L:=Length(aName); + If (aName[1]=FExprStart) and (aName[L]=FExprEnd) then + begin + Result:=TMustacheExprElement.Create(metVariable,aParent,aPosition); + Result.Data:=Copy(aName,2,L-2); + ExprParser.Expression:=Result.Data; + ExprParser.ExtractNode(N); + TMustacheExprElement(Result).SetNode(N); + aParent.AddChild(Result); + end + else + Result:=Inherited CreateDefault(aParent,aPosition,aName); +end; + +constructor TMustacheExprParser.Create(aTemplate: TMustacheString; + aStart: TMustacheString; aStop: TMustacheString); +begin + inherited Create(aTemplate, aStart, aStop); + FExprStart:='['; + FExprEnd:=']'; +end; + +{ TMustacheExpr } + +procedure TMustacheExpr.SetExprEndChar(AValue: String); +begin + if FExprEndChar=AValue then Exit; + if Length(aValue)<>1 then + EMustache.Create(SErrLengthStartMustBe1); + FExprEndChar:=AValue; +end; + +function TMustacheExpr.GetExpressionParser(aOwner : TComponent): TFPExpressionParser; +begin + Result:=TMustacheExpressionParser.Create(AOwner); +end; + +procedure TMustacheExpr.SetExpressionParser(AValue: TFPExpressionParser); + +begin + if FExpressionParser=AValue then Exit; + If assigned(FExpressionParser) then + FExpressionParser.RemoveFreeNotification(Self); + FExpressionParser:=AValue; + If assigned(FExpressionParser) then + FExpressionParser.FreeNotification(Self); +end; + +procedure TMustacheExpr.SetExprStartChar(AValue: String); +begin + if FExprStartChar=AValue then Exit; + if Length(aValue)<>1 then + EMustache.Create(SErrLengthEndMustBe1); + FExprStartChar:=AValue; +end; + +function TMustacheExpr.DoGetExpressionParser: TFPExpressionParser; +begin + if FExpressionParser=Nil then + begin + FExpressionParser:=GetExpressionParser(Self); + FExpressionParser.SetSubComponent(True); + FExpressionParser.FreeNotification(Self); + end; + Result:=FExpressionParser; +end; + +procedure TMustacheExpr.Notification(AComponent: TComponent; + Operation: TOperation); +begin + inherited Notification(AComponent, Operation); + if (Operation=opRemove) and (aComponent=FExpressionParser) then + FExpressionParser:=Nil; +end; + +function TMustacheExpr.CreateParser(aTemplate: TMustacheString ): TMustacheParser; + +Var + Exp : TMustacheExprParser; + +begin + Exp:=TMustacheExprParser.Create(aTemplate); + Exp.ExprParser:=Self.ExpressionParser; + Result:=Exp; +end; + +constructor TMustacheExpr.Create(aOwner: TComponent); +begin + inherited Create(aOwner); + DoGetExpressionParser; +end; + +procedure TMustacheExpr.Render(aContext: TMustacheContext; aOutput: TMustacheOutput); + +begin + FCurrentContext:=aContext; + try + inherited Render(aContext, aOutput); + finally + FCurrentContext:=nil; + end; +end; + +procedure TMustacheExpr.DoGetVariable(var Result: TFPExpressionResult; ConstRef + AName: ShortString); + +Var + S : TMustacheString; + V : Double; + C : Integer; + +begin + If not Assigned(FCurrentContext) then + case result.ResultType of + rtInteger : Result.ResInteger:=0; + rtDateTime : Result.ResDateTime:=0.0; + rtString : Result.ResString:=''; + rtFloat: Result.ResFloat:=0.0; + rtCurrency: Result.ResCurrency:=0.0; + rtBoolean: Result.ResBoolean:=False; + end + else + begin + S:=FCurrentContext.GetTextValue(aName); + case result.ResultType of + rtInteger : Result.ResInteger:=StrToInt64Def(S,0); + rtDateTime : if Not TryStrToDateTime(S,Result.ResDateTime) then + Result.ResDateTime:=0.0; + rtString : Result.ResString:=S; + rtFloat: begin + Val(S,V,C); + if C<>0 then + Result.ResFloat:=0.0 + else + Result.ResFloat:=V; + end; + rtCurrency: + begin + Val(S,V,C); + if (C<>0) then + Result.ResCurrency:=0.0 + else + Result.ResCurrency:=V; + end; + rtBoolean: Result.ResBoolean:=StrToBoolDef(S,False); + end; + end; +end; + +function TMustacheExpr.GetResultType(aValue: TJSONData): TResultType; + +begin + Case aValue.JSONType of + jtBoolean : Result:=rtBoolean; + jtString, + jtArray, + jtObject, + jtNull : Result:=rtString; + jtNumber : + begin + Case TJSONNumber(aValue).NumberType of + ntFloat : Result:=rtFloat; + ntInteger, + ntInt64 : Result:=rtInteger; + ntQWord : Raise EMustache.Create('Unsupported JSON type'); + end; + end; + end; +end; + +procedure TMustacheExpr.RegisterVariables(aContext: TMustacheJSONContext; + aPath: TJSONStringType; UseEvent: Boolean); + +begin + RegisterVariables(aContext.RootData as TJSONObject,aPath,UseEvent); +end; + +procedure TMustacheExpr.RegisterVariables(aJSON: String; + aPath: TJSONStringType; UseEvent: Boolean); + +Var + aData : TJSONData; + aObj : TJSONObject absolute aData; + + +begin + aData:=getJSON(aJSON,True); + try + if aData is TJSONObject then + RegisterVariables(aObj,aPath,useEvent) + else + Raise EMustache.Create('Invalid JSON data to register variables'); + finally + aData.Free; + end; +end; + +procedure TMustacheExpr.RegisterVariables(aJSON: TJSONObject; aPath: TJSONStringType; UseEvent: Boolean); + +Var + aData,aValue : TJSONData; + aEnum : TJSONEnum; + aKey : TJSONStringType; + rt : TResultType; + aParser : TFPExpressionParser; + +begin + aParser:=ExpressionParser; + aData:=aJSON.FindPath(aPath); + if aData is TJSONObject then + for aEnum in aData do + begin + aKey:=aEnum.Key; + aValue:=aEnum.Value; + rt:=GetResultType(aValue); + if UseEvent then + aParser.Identifiers.AddVariable(aKey,rt,@DoGetVariable) + else + case rt of + rtBoolean: aParser.Identifiers.AddBooleanVariable(aKey,aValue.AsBoolean); + rtFloat: aParser.Identifiers.AddFloatVariable(aKey,aValue.AsFloat); + rtInteger: aParser.Identifiers.AddIntegerVariable(aKey,aValue.AsInteger); + rtString: Case aValue.JSONType of + jtNull: aParser.Identifiers.AddStringVariable(aKey,''); + jtArray, + jtObject: aParser.Identifiers.AddStringVariable(aKey, aValue.AsJSON); + else + aParser.Identifiers.AddStringVariable(aKey,aValue.AsString); + end; + end; + end; +end; + +end. + diff --git a/packages/fcl-mustache/src/fpmustache.pp b/packages/fcl-mustache/src/fpmustache.pp new file mode 100644 index 0000000000..37163a3ded --- /dev/null +++ b/packages/fcl-mustache/src/fpmustache.pp @@ -0,0 +1,1340 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + This file contains a Mustache parser and renderer. + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit fpmustache; + +{$mode objfpc}{$H+} +{$WARN 5024 off : Parameter "$1" not used} +interface + +uses + Classes, SysUtils, fpjson; + +Type + EMustache = Class(Exception); + + TMustacheString = UTF8String; + TMustacheChar = AnsiChar; + TMustacheContext = class; + + TMustacheOutput = Class(TObject) + Public + // add atext to output + Procedure Output(Const aText : TMustacheString); virtual; abstract; + Procedure Reset; virtual; abstract; + end; + + { TMustacheStringOutput } + + TMustacheStringOutput = Class(TMustacheOutput) + private + FData: TMustacheString; + Public + // Override + Procedure Output(Const aText : TMustacheString); override; + Procedure Reset; override; + // The rendered TMustacheString + Property Data : TMustacheString Read FData; + end; + + { TMustacheElement } + + TMustacheElementType = (metRoot,metComment,metText,metVariable,metSection,metInvertedSection,metPartial); + + TMustacheElement = Class(TObject) + private + FPosition: Integer; + FType : TMustacheElementType; + FParent : TMustacheElement; + Protected + function GetCount: Integer; virtual; + function GetElement(aIndex : Integer): TMustacheElement; virtual; + Function GetData : TMustacheString ; virtual; abstract; + Procedure SetData(Const aData : TMustacheString) ; virtual; abstract; + Function GetPrefix : TMustacheString; virtual; + Procedure SetPrefix (aValue : TMustacheString); virtual; + Procedure Dump(aList : Tstrings; aIndent : TMustacheString; aDumpChildren : Boolean = true); virtual; + Public + Constructor Create(aType : TMustacheElementType; aParent : TMustacheElement;aPosition : Integer); virtual; + // Add a child. Parent always owns child + Procedure AddChild(aChild : TMustacheElement); virtual; + // Render the text for this element + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); virtual; abstract; + // Position in template + Property Position : Integer Read FPosition; + // Parent element + Property Parent : TMustacheElement Read FParent; + // Access to children + Property Children[aIndex : Integer] : TMustacheElement Read GetElement; + // Child count + Property ChildCount : Integer Read GetCount; + // Element type + Property ElementType : TMustacheElementType Read FType; + // The data for this element. What this is, depends on the kind. + // etText : the text; + // etValue : the variable name + // etSection : the section name. + // etInvertedSection : the section name. + Property Data : TMustacheString Read GetData Write SetData; + // Whitespace prefix. Normally only used for partials + Property Prefix : TMustacheString Read GetPrefix Write SetPrefix; + end; + TMustacheElementClass = Class of TMustacheElement; + TMustacheElementArray = Array of TMustacheElement; + + { TMustacheNamedElement } + + TMustacheNamedElement = Class(TMustacheElement) + private + FName: TMustacheString; + Protected + Procedure SetData(Const aData : TMustacheString); override; + Function GetData : TMustacheString; override; + Public + Property Name : TMustacheString Read FName; + end; + + { TMustacheParentElement } + + TMustacheParentElement = Class(TMustacheNamedElement) + Private + FChildren : TMustacheElementArray; + FCount : Integer; + Protected + function GetElement(aIndex : Integer): TMustacheElement; override; + function GetCount : Integer; override; + Public + Destructor Destroy; override; + Procedure AddChild(aChild : TMustacheElement); override; + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + end; + + + { TMustacheTextElement } + + TMustacheTextElement = Class(TMustacheElement) + Private + FData : TMustacheString; + Protected + Procedure SetData(Const aData : TMustacheString) ; override; + Function GetData : TMustacheString; override; + Public + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + end; + + { TMustacheVariableElement } + + TMustacheVariableElement = Class(TMustacheNamedElement) + private + FNoUnescape: Boolean; + Protected + Procedure SetData(Const aData : TMustacheString); override; + Public + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + Property NoUnescape : Boolean Read FNoUnescape; + end; + + { TMustacheSectionElement } + + TMustacheSectionElement = Class(TMustacheParentElement) + Public + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + end; + + { TMustachePartialElement } + + TMustachePartialElement = Class(TMustacheElement) + Private + FPrefix : TMustacheString; + FPartialName : TMustacheString; + FPartial : TMustacheElement; + Protected + Function GetData : TMustacheString ; override; + Procedure SetData(Const aData : TMustacheString) ; override; + Procedure Dump(aList : Tstrings; aIndent : TMustacheString; aDumpChildren : Boolean = true); override; + Function GetPrefix : TMustacheString; override; + Procedure SetPrefix (aValue : TMustacheString); override; + Public + Destructor Destroy; override; + Procedure AddChild(aChild: TMustacheElement); override; + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override; + Property Partial : TMustacheElement Read FPartial; + end; + + { TMustachePartialList } + + TMustachePartialList = Class(TMustacheParentElement) + Public + Function FindPartial(aName : TMustacheString) : TMustacheElement; + end; + + { TMustacheParser } + TGetTextValueEvent = Procedure (Const aName : TMustacheString; var aHandled : Boolean; var aValue : TMustacheString) of Object; + + TMustacheParser = Class(TObject) + private + FStopTag: TMustacheString; + FStartTag: TMustacheString; + FTemplate: TMustacheString; + FOnGetPartial: TGetTextValueEvent; + FPartials: TMustachePartialList; + Class var DefaultTypes : Array[TMustacheElementType] of TMustacheElementClass; + Protected + // Called to create a default element for a {{ }} tag. By default creates a variable. + // Override this if you want to create additional elements. + function CreateDefault(aParent: TMustacheElement; aPosition: Integer; const aName: String): TMustacheElement; virtual; + // Create element for indicated type, must add it to parent. + // You can override this to provide customized behaviour. + function CreateElement(aType: TMustacheElementType; aParent: TMustacheElement; aPosition: Integer): TMustacheElement; virtual; + // Parse + Procedure DoParse(aParent : TMustacheElement; Const aTemplate, aStart, aStop : TMustacheString); virtual; + // Called to get the template of a partial. The template is parsed, and the result added to the partials list. + Function GetPartial(const aName : TMustacheString) : TMustacheString; virtual; + // Auxuliary functions for the peculiar whitespace handling of Mustache specs... + function EndsOnWhiteSpace(aElement: TMustacheElement): Boolean; virtual; + function GetEndingWhiteSpace(aElement: TMustacheElement): TMustacheString; virtual; + procedure ExtractStartStop(const aName: TMustacheString; out aStart, aStop: TMustacheString); virtual; + procedure TrimEndingWhiteSpace(aElement: TMustacheElement); virtual; + Public + // Create a new parser. + Constructor Create(aTemplate : TMustacheString = '';aStart: TMustacheString='';aStop: TMustacheString = ''); virtual; + // Set the default TMustacheElements for the descendents + Class procedure SetDefaultTypeClass(aType : TMustacheElementType; aClass: TMustacheElementClass); + // Parse the template and + Procedure Parse(aParent : TMustacheElement); + Function Parse : TMustacheElement; + // Will be used to hold partials. You must set this before calling Parse. + Property Partials : TMustachePartialList Read FPartials Write FPartials; + // The template created on startup + Property Template : TMustacheString Read FTemplate write FTemplate; + // The initial start tag marker, by default {{ + Property StartTag : TMustacheString Read FStartTag Write FStartTag; + // The initial end tag marker, by default }} + Property StopTag : TMustacheString Read FStopTag Write FSTopTag; + // Event called to get the source of a partial. + Property OnGetPartial : TGetTextValueEvent Read FOnGetPartial Write FOnGetPartial; + end; + + { TMustacheContext } + TMustacheSectionType = (mstNone,mstSingle,mstList); + + TMustacheContext = Class(TObject) + Private + FCallback : TGetTextValueEvent; + Public + Constructor Create(aCallback : TGetTextValueEvent); virtual; + // Helper function to quote HTML + Class Function QuoteHTML(aString : TMustacheString) :TMustacheString; virtual; + // Move to next section item. aName is section name. Returns True if move successful + Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; virtual; + // Push a new section context with name aName. + Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; virtual; + // Pop current section. aName is for verification. + Procedure PopSection(Const aName : TMustacheString); virtual; + // Return the value of a variable with name aName. + Function GetTextValue(Const aName : TMustacheString) : TMustacheString; virtual; + end; + + { TMustacheJSONContext } + + TMustacheJSONContext = Class(TMustacheContext) + Private + Type + TPair = Record + Index : Integer; // if array, index of current element. + Value : TJSONData; + end; + Private + FCurrentData: TJSONData; + FStack : Array of TPair; + FCount : Integer; + Function FindValue(Const aName : TMustacheString) : TJSONData; + function GetRootData: TJSONData; + Public + Constructor Create(aJSON : TJSONData; aCallback : TGetTextValueEvent); reintroduce; + Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override; + Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override; + Procedure PopSection(Const aName : TMustacheString); override; + Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override; + Property RootData : TJSONData read GetRootData; + end; + + TMustache = Class(TComponent) + private + FCompiled: TMustacheElement; + FCompiledPartials: TMustachePartialList; + FOnGetValue: TGetTextValueEvent; + FPartials: TStrings; + FStartTag: TMustacheString; + FStopTag: TMustacheString; + FTemplate: TMustacheString; + procedure SetPartials(AValue: TStrings); + procedure SetStartTag(AValue: TMustacheString); + procedure SetStopTag(AValue: TMustacheString); + procedure SetTemplate(AValue: TMustacheString); + Protected + Procedure DoGetPartial(Const aName : TMustacheString; var aHandled : Boolean; var aValue : TMustacheString); virtual; + Procedure Reset; virtual; + Function CreatePartials : TMustachePartialList; + function CreateParser(aTemplate: TMustacheString): TMustacheParser; virtual; + Property Compiled : TMustacheElement Read FCompiled; + Property CompiledPartials : TMustachePartialList Read FCompiledPartials; + Public + Constructor Create(aOwner : TComponent); override; + Destructor Destroy; override; + Procedure Compile; + Procedure Dump(aList : Tstrings; aindent : TMustacheString); overload; virtual; + Function Dump: TMustacheString;overload; + Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput); virtual; overload; + Function Render(aContext : TMustacheContext) : TMustacheString; overload; + Function Render(const aJSON : TJSONData) : TMustacheString; overload; + Function Render(const aJSON : TJSONStringType) : TMustacheString; overload; + Class function CreateMustache(aOwner: TComponent; aTemplate: TMustacheString): TMustache; virtual; + Class Function Render(aTemplate : TMustacheString; const aJSON : TJSONStringType) : TMustacheString; + Published + Property Template : TMustacheString Read FTemplate Write SetTemplate; + Property OnGetValue : TGetTextValueEvent Read FOnGetValue Write FOnGetValue; + Property StartTag : TMustacheString Read FStartTag Write SetStartTag; + Property StopTag : TMustacheString Read FStopTag Write SetStopTag; + Property Partials : TStrings Read FPartials Write SetPartials; + end; + + +Const + ListGrowCount = 10; + JSONListGrowCount = 10; + +implementation + +uses TypInfo; + + + +Resourcestring + SErrNoChildForElement = 'Class %s does not support child elements.'; + SErrInvalidIndex= '%s: Index %d is not in valid range [0..%d].'; + SErrUnterminatedTag = 'Tag %s opened on position %d but not closed.'; + SErrEmptyTag = 'Tag %s on position %d is empty.'; + SErrSectionClose = 'Structural error: Section "%s" on position %d is closed by tag "%s" on position %d.'; + SErrNotClosedSection = 'Structural error: Section "%s" on position %d is not closed.'; + SErrNoSectionToClose = 'Structural error: Section "%s" on position %d was never opened.'; + SErrInvalidDelimiter = 'Invalid set delimiter: %s'; + SErrInvalidDelimiterValue = 'Invalid set delimiter %s value: %s in "%s"'; + SErrNoPartials = 'No partials list'; + + // SErrPartialNotFound = 'Partial "%s" not found.'; + SStartTag = 'Start'; + SStopTag = 'Stop'; + +{ TMustachePartialList } + +function TMustachePartialList.FindPartial(aName: TMustacheString ): TMustacheElement; + +Var + I : Integer; + +begin + Result:=Nil; + I:=ChildCount-1; + While (Result=Nil) and (I>=0) do + begin + Result:=Children[I]; + If (Result.Data<>aName) then + Result:=Nil; + Dec(I); + end; +end; + +{ TMustachePartialElement } + +function TMustachePartialElement.GetData: TMustacheString; +begin + Result:=FPartialName; +end; + +procedure TMustachePartialElement.SetData(const aData: TMustacheString); +begin + FPartialName:=aData; +end; + +procedure TMustachePartialElement.AddChild(aChild: TMustacheElement); +begin + If (FPartial<>Nil) and (aChild<>Nil) then + Raise EMustache.Create('Cannot set partial twice'); + FPartial:=aChild; +end; + +procedure TMustachePartialElement.Dump(aList: Tstrings; + aIndent: TMustacheString; aDumpChildren: Boolean); +begin + inherited Dump(aList, aIndent, aDumpChildren); + if Prefix<>'' then + aList[aList.Count-1]:=aList[aList.Count-1]+' Prefix: "'+Prefix+'"'; +end; + +function TMustachePartialElement.GetPrefix: TMustacheString; +begin + Result:=FPrefix; +end; + +procedure TMustachePartialElement.SetPrefix(aValue: TMustacheString); +begin + FPrefix:=aValue; +end; + +procedure TMustachePartialElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); + +begin + FPartial.Render(aContext,aOutput,Prefix); +end; + +destructor TMustachePartialElement.Destroy; +begin + inherited Destroy; +end; + + +{ TMustache } + +function TMustache.CreateParser(aTemplate : TMustacheString): TMustacheParser; +begin + Result:=TMustacheParser.Create(aTemplate); +end; + +constructor TMustache.Create(aOwner: TComponent); +begin + Inherited; + FPartials:=TStringList.Create; + FCompiledPartials:=CreatePartials; +end; + +destructor TMustache.Destroy; +begin + Reset; + FreeAndNil(FPartials); + FreeAndNil(FCompiledPartials); + inherited Destroy; +end; + +procedure TMustache.Compile; + +Var + Parser : TMustacheParser; + +begin + Parser:=CreateParser(Self.Template); + try + Parser.OnGetPartial:=@DoGetPartial; + //Parser.Template:=Self.Template; + Parser.Partials:=Self.FCompiledPartials; + if Self.StartTag<>'' then + Parser.StartTag:=Self.StartTag; + if Self.StopTag<>'' then + Parser.StopTag:=Self.StopTag; + FCompiled:=Parser.Parse; + finally + Parser.Free; + end; +end; + +procedure TMustache.Dump(aList: Tstrings; aindent: TMustacheString); +begin + if Assigned(Compiled) then + Compiled.Dump(aList,aIndent); +end; + +function TMustache.Dump: TMustacheString; + +Var + I : integer; + L : TStrings; + +begin + L:=TStringList.Create; + try + Dump(L,''); + if Partials.Count>0 then + begin + L.Add('Partials:'); + for I:=0 to Partials.Count-1 do + L.Add('Partial '+IntToStr(I)+': '+Partials[i]); + L.Add('End of partials'); + end; + Result:=L.Text; + finally + L.Free; + end; +end; + +procedure TMustache.Render(aContext: TMustacheContext; aOutput: TMustacheOutput); + +begin + if not Assigned(Compiled) then + Compile; + Compiled.Render(aContext,aOutput); +end; + +function TMustache.Render(aContext: TMustacheContext): TMustacheString; + +Var + S : TMustacheStringOutput; + +begin + S:=TMustacheStringOutput.Create; + try + Render(aContext,S); + Result:=S.Data; + finally + S.Free; + end; +end; + +function TMustache.Render(const aJSON: TJSONData): TMustacheString; + +Var + C : TMustacheJSONContext; + +begin + C:=TMustacheJSONContext.Create(aJSON,FOnGetValue); + try + Result:=Render(C); + finally + C.Free; + end; +end; + +function TMustache.Render(const aJSON: TJSONStringType): TMustacheString; + +Var + JSONData : TJSONData; + +begin + JSONData:=GetJSON(aJSON); + try + Result:=Render(JSONData); + finally + JSONData.Free; + end; +end; + +class function TMustache.CreateMustache(aOwner : TComponent; aTemplate : TMustacheString) : TMustache; + +begin + Result:=TMustache.Create(aOwner); + Result.Template:=aTemplate; +end; + +procedure TMustache.SetStartTag(AValue: TMustacheString); +begin + if FStartTag=AValue then Exit; + FStartTag:=AValue; + Reset; +end; + +procedure TMustache.SetPartials(AValue: TStrings); +begin + if FPartials=AValue then Exit; + FPartials.Assign(AValue); +end; + +procedure TMustache.SetStopTag(AValue: TMustacheString); +begin + if FStopTag=AValue then Exit; + FStopTag:=AValue; + Reset; +end; + +procedure TMustache.SetTemplate(AValue: TMustacheString); +begin + if FTemplate=AValue then Exit; + FTemplate:=AValue; + Reset; +end; + +procedure TMustache.DoGetPartial(const aName: TMustacheString; + var aHandled: Boolean; var aValue: TMustacheString); +begin + aValue:=FPartials.Values[aName]; + aHandled:=aValue<>''; + if Not aHandled then + aHandled:=FPartials.IndexOfName(aName)<>-1; +end; + +procedure TMustache.Reset; +begin + FreeAndNil(FCompiled); + FreeAndNil(FCompiledPartials); + FCompiledPartials:=CreatePartials; +end; + +function TMustache.CreatePartials: TMustachePartialList; +begin + Result:=TMustachePartialList.Create(metRoot,Nil,0); +end; + +class function TMustache.Render(aTemplate: TMustacheString; + const aJSON: TJSONStringType): TMustacheString; + +begin + With CreateMustache(Nil,aTemplate) do + try + Result:=Render(aJSON); + finally + Free; + end; +end; + +{ TMustacheJSONContext } + +function TMustacheJSONContext.FindValue(const aName: TMustacheString + ): TJSONData; +Var + aCount : Integer; + N : TMustacheString; + +begin + Result:=Nil; + aCount:=FCount-1; + While (Result=Nil) and (aCount>=0) do + begin + N:=aName; + if N='.' then + N:=''; + With FStack[aCount] do + if (Index>=0) and (Index<Value.Count) then + Result:=Value.Items[Index].FindPath(N) + else + Result:=Value.FindPath(N); + Dec(aCount); + end; +end; + +function TMustacheJSONContext.GetRootData: TJSONData; +begin + Result:=FStack[0].Value; +end; + + +constructor TMustacheJSONContext.Create(aJSON: TJSONData; + aCallback: TGetTextValueEvent); +begin + Inherited Create(aCallBack); + SetLength(FStack,JSONListGrowCount); + FStack[0].Value:=aJSON; + FStack[0].Index:=-1; + FCount:=1; +end; + +function TMustacheJSONContext.MoveNextSectionItem(const aName: TMustacheString + ): Boolean; + +begin + With FStack[FCount-1] do + begin + Inc(Index); + Result:=Index<Value.Count; + end; +end; + +function TMustacheJSONContext.PushSection(const aName: TMustacheString + ): TMustacheSectionType; + +Var + S : TJSONData; + +begin + Result:=mstNone; + S:=FindValue(aName); + if S=Nil then + Exit; + if (S.JSONType=jtArray) then + begin + if (S.Count>0) then + Result:=mstList + end + else if Not ((S.JSONType=jtNull) or ((S.JSONType=jtBoolean) and Not S.AsBoolean)) then + Result:=mstSingle; + if Result<>mstNone then + begin + if FCount=Length(FStack) then + SetLength(FStack,FCount+JSONListGrowCount); + FStack[FCount].Value:=S; + FStack[FCount].Index:=-1; + Inc(FCount,1); + end; +end; + +procedure TMustacheJSONContext.PopSection(const aName: TMustacheString); +begin + if FCount<1 then + Raise EMustache.CreateFmt('PopSection %s without push',[aName]); + Dec(FCount,1); +end; + +function TMustacheJSONContext.GetTextValue(const aName: TMustacheString): TMustacheString; + +Var + aJSON : TJSONData; + +begin + Result:=''; + aJSON:=FindValue(aName); + if not Assigned(aJSON) then + Result:=Inherited GetTextValue(aName) + else + if (AJSON.JSONType=jtNumber) and (TJSONNumber(aJSON).NumberType=ntFloat) then + Result:=FormatFloat('0.0###########',aJSON.AsFloat) + else + Result:=aJSON.AsString; +end; + +{ TMustacheSectionElement } + +procedure TMustacheSectionElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False); + +Var + L : TMustacheSectionType; + +begin + L:=aContext.PushSection(Name); + if ElementType=metInvertedSection then + begin + if L=mstNone then + inherited Render(aContext, aOutput,aPrefix); + end + else + Case L of + mstSingle : + inherited Render(aContext, aOutput); + mstList : + while aContext.MoveNextSectionItem(Name) do + inherited Render(aContext, aOutput,aPrefix); + end; + if L<>mstNone then + aContext.PopSection(Name); +end; + +{ TMustacheContext } + +constructor TMustacheContext.Create(aCallback: TGetTextValueEvent); +begin + FCallback:=aCallback; +end; + +class function TMustacheContext.QuoteHTML(aString: TMustacheString + ): TMustacheString; + +Const + QuoteChars = ['<','>','&','"']; + +Var + I,Last,Len : Integer; + Res : TMustacheString; + + Procedure AddToResult; overload; + + begin + Res:=Res+Copy(aString,Last,I-Last); + Last:=I; + end; + + Procedure AddToResult(aTerm : TMustacheString); overload; + + begin + Res:=Res+aTerm; + Last:=Last+1; + end; + +begin + Res:=''; + Last:=1; + Len:=Length(Astring); + I:=1; + While (I<=Len) do + begin + While (I<=Len) and not (aString[i] in QuoteChars) do + Inc(I); + AddToResult; + if I<=Len then + Case aString[i] of + '<' : AddToResult('<'); + '>' : AddToResult('>'); + '&' : AddToResult('&'); + '"' : AddToResult('"'); + end; + Inc(i); + end; + AddToResult; + Result:=Res; +end; + +function TMustacheContext.MoveNextSectionItem(const aName: TMustacheString): Boolean; +begin + Result:=False +end; + +function TMustacheContext.PushSection(const aName: TMustacheString): TMustacheSectionType; +begin + Result:=mstNone; +end; + +procedure TMustacheContext.PopSection(const aName: TMustacheString); +begin + // +end; + +function TMustacheContext.GetTextValue(const aName: TMustacheString): TMustacheString; + +var + aHandled : Boolean; + +begin + aHandled:=False; + Result:=''; + if Assigned(FCallBack) then + FCallBack(aName,aHandled,Result); +end; + +{ TMustacheTextElement } + +procedure TMustacheTextElement.SetData(const aData: TMustacheString); +begin + FData:=aData; +end; + +function TMustacheTextElement.GetData: TMustacheString; +begin + Result:=FData; +end; + +procedure TMustacheTextElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False); + +Var + S : String; + L : Integer; + +begin + if (ElementType=metText) then + begin + S:=FData; + L:=Length(S); + if (aPrefix<>'') then + begin + if (S[L]=#10) and aLast then + S:=StringReplace(Copy(S,1,L-1),#10,#10+aPrefix,[rfReplaceAll])+#10 + else + S:=StringReplace(S,#10,#10+aPrefix,[rfReplaceAll]); +{$IFDEF DEBUGMUSTACHE} + Writeln('Adding prefix =]',aPrefix,'[= to =]',FData, '[= ---> =]',S,'["'); +{$ENDIF} + end; + aOutput.Output(S); + end; +end; + +{ TMustacheVariableElement } + +procedure TMustacheVariableElement.SetData(const aData: TMustacheString); + +Var + L : Integer; + N : TMustacheString; +begin + N:=aData; + L:=Length(N); + FNoUnescape:=(L>1) and (N[1]='{') and (N[L]='}'); + if NoUnescape then + N:=Copy(N,2,L-2) + else + begin + FNoUnescape:=(L>0) and (N[1]='&'); + if NoUnescape then + N:=Copy(N,2,L-1); + end; + inherited SetData(N); +end; + +procedure TMustacheVariableElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False); + +Var + aValue : TMustacheString; + +begin + aValue:=''; + if Assigned(aContext) then + begin + aValue:=aContext.GetTextValue(Name); + if Not NoUnescape then + aValue:=aContext.QuoteHTML(aValue); + end; + aOutput.Output(aValue); +end; + +{ TMustacheParser } + +function TMustacheParser.CreateElement(aType: TMustacheElementType; aParent : TMustacheElement; aPosition : Integer): TMustacheElement; + +begin + Result:=DefaultTypes[aType].Create(aType,aParent,aPosition); + if Assigned(aParent) then + aParent.AddChild(Result); +end; + +constructor TMustacheParser.Create(aTemplate: TMustacheString; aStart: TMustacheString; + aStop: TMustacheString); +begin + FStartTag:=aStart; + FStopTag:=aStop; + FTemplate:=aTemplate; + if FStartTag='' then + FStartTag:='{{'; + if FStopTag='' then + FStopTag:='}}'; +end; + +class procedure TMustacheParser.SetDefaultTypeClass(aType: TMustacheElementType; + aClass: TMustacheElementClass); + +begin + DefaultTypes[aType]:=aClass; +end; + +function TMustacheParser.GetPartial(const aName: TMustacheString): TMustacheString; + +Var + Handled : Boolean; +begin + Result:=''; + Handled:=False; + if Assigned(FOnGetPartial) then + FOnGetPartial(aName,Handled,Result); +// If not Handled then +// Raise EMustache.CreateFmt(SErrPartialNotFound,[aName]); +end; + +procedure TMustacheParser.ExtractStartStop(const aName: TMustacheString; out aStart, + aStop: TMustacheString); + + Function Invalid(S : TMustacheString) : Boolean; + begin + Invalid:=(Length(S)=0) or (Pos('=',S)<>0); + end; + +Var + DLen,NLen : Integer; + N : TMustacheString; + +begin + NLen:=Length(aName); + if aName[NLen]<>'=' then + Raise EMustache.CreateFmt(SErrInvalidDelimiter,[aName]); + N:=Copy(aName,1,NLen-1); + DLen:=(NLen-1) div 2; + aStart:=Trim(Copy(N,1,DLen)); + aStop:=Trim(Copy(N,NLen-DLen,DLen)); + // Writeln('New: "',aStart,'" - "',aStop,'" - ',DLEn); + if Invalid(aStop) then + Raise EMustache.CreateFmt(SErrInvalidDelimiterValue,[SStopTag,aStop,N]); + if Invalid(aStart) then + Raise EMustache.CreateFmt(SErrInvalidDelimiterValue,[SStartTag,aStart,N]); +end; + +procedure TMustacheParser.Parse(aParent: TMustacheElement); + +begin + DoParse(aParent,FTemplate,StartTag, StopTag); +end; + +function TMustacheParser.EndsOnWhiteSpace(aElement: TMustacheElement): Boolean; + +Var + I : Integer; + S : TMustacheString; + +begin + // if on standalone line, the entire line must be removed, see specs comments.standalone + Result:=(aElement.ElementType=metText); + s:=aElement.Data; + I:=Length(S); + While Result and (I>0) do + begin + if S[i] in [#13,#10] then + Break; + Result:=(S[I]=' '); + Dec(i); + end; + Result:=Result and ((I>0) or (aElement.Position=1)); +end; + +function TMustacheParser.GetEndingWhiteSpace(aElement: TMustacheElement): TMustacheString; + +Var + S : TMustacheString; + I : Integer; + +begin + s:=aElement.Data; + I:=Length(S); + While (I>0) and (S[I]=' ') do + Dec(i); + Result:=Copy(S,I+1); +end; + +procedure TMustacheParser.TrimEndingWhiteSpace(aElement: TMustacheElement); + +Var + I : Integer; + S : TMustacheString; + +begin + s:=aElement.Data; + I:=Length(S); + While (I>0) and (S[I]=' ') do + Dec(i); + aElement.Data:=Copy(S,1,I); +end; + +Function TMustacheParser.CreateDefault(aParent : TMustacheElement; aPosition : Integer;Const aName : String) : TMustacheElement; + +begin + Result:=CreateElement(metVariable,aParent,aPosition); + Result.SetData(aName); +end; + +procedure TMustacheParser.DoParse(aParent: TMustacheElement; const aTemplate, + aStart, aStop: TMustacheString); + +Var + currParent : TMustacheElement; + aLen,clStop, lStart,lStop, NewPos, Current, Total : Integer; + aName,cStart,cStop,R : TMustacheString; + C: TMustacheChar; + IsWhiteSpace : Boolean; + Partial,WhiteSpaceEl : TMustacheELement; + + Function CheckWhiteSpace : Boolean; + + begin + WhiteSpaceEl:=Nil; + With CurrParent do + begin + Result:=(ChildCount=0) or EndsOnWhiteSpace(Children[ChildCount-1]); + if Result and (ChildCount>0) then + WhiteSpaceEl:=Children[ChildCount-1]; + end; + end; + + Procedure FinishWhiteSpace(Full : Boolean = true); + Var + I : Integer; + begin + I:=NewPos; + While IsWhiteSpace and (I+clStop<=Total) do + begin + C:=aTemplate[I+clStop]; + if (C in [#13,#10]) then + Break; + isWhiteSpace:=aTemplate[I+clStop]=' '; + I:=I+1; + end; + if isWhiteSpace then + begin + While (I<=Total) and (aTemplate[I+clStop] in [#13,#10]) do + Inc(I); + NewPos:=I; + if Assigned(WhiteSpaceEl) and full then + TrimEndingWhiteSpace(WhiteSpaceEl); + end; + end; + +begin + currParent:=aParent; + cStart:=aStart; + cStop:=aStop; + lStart:=Length(cStart); + lStop:=Length(cStop); + Current:=1; + Total:=Length(aTemplate); + While (Current<=Total) do + begin + C:=Template[Current]; + NewPos:=Pos(cStart,aTemplate,Current); + if NewPos=0 then + NewPos:=Total+1; + // Stash what we have till now. + if NewPos>Current then + begin + R:=Copy(aTemplate,Current,NewPos-Current); + CreateElement(metText,currParent,Current).SetData(R); + Current:=NewPos; + end; + if Current<Total then + begin + NewPos:=Pos(cStop,aTemplate,Current+lStart); + if (NewPos=0) then + Raise EMustache.CreateFmt(SErrUnterminatedTag,[cStart,Current]); + aLen:=NewPos-Current-LStart; + aName:=Copy(aTemplate,Current+LStart,ALen); + if (aName='') then + Raise EMustache.CreateFmt(SErrEmptyTag,[cStart,Current]); + C:=aName[1]; + if C in ['=','#','^','/','!','>'] then + aName:=Copy(aName,2,Length(aName)-1); + clStop:=Lstop; // Can change. + case C of + '=' : + begin + IsWhiteSpace:=CheckWhiteSpace; + if IsWhiteSpace then + FinishWhiteSpace; + ExtractStartStop(aName,cStart,cStop); + lStart:=Length(cStart); + lStop:=Length(cStop); + //R:=Copy(aTemplate,newPos+clStop); + //Writeln(R); + end; + '{' : + begin + if (cStop='}}') then + begin + if (FTemplate[NewPos+lStop]<>'}') then + Raise EMustache.CreateFmt(SErrUnterminatedTag,[cStart,Current]); + inc(NewPos); + aName:=aName+'}'; + end; + CreateElement(metVariable,currParent,Current).SetData(aName); + end; + '#' : + begin + IsWhiteSpace:=CheckWhiteSpace; + CurrParent:=CreateElement(metSection,currParent,Current); + CurrParent.SetData(aName); + if IsWhiteSpace then + FinishWhiteSpace; + end; + '!' : + begin + IsWhiteSpace:=CheckWhiteSpace; + CreateElement(metComment,currParent,Current).SetData(aName); + if IsWhiteSpace then + FinishWhiteSpace; + end; + '^' : + begin + IsWhiteSpace:=CheckWhiteSpace; + CurrParent:=CreateElement(metInvertedSection,currParent,Current); + CurrParent.SetData(aName); + if IsWhiteSpace then + FinishWhiteSpace; + end; + '>' : + begin + // Find or create compiled partial; + IsWhiteSpace:=CheckWhiteSpace; + aName:=Trim(aName); + if not Assigned(Partials) then + Raise EMustache.Create(SErrNoPartials); + Partial:=Partials.FindPartial(aName); + if Partial=Nil then + begin + Partial:=CreateElement(metRoot,Partials,Current); + Partial.Data:=aName; + DoParse(Partial,GetPartial(aName),FStartTag,FStopTag); + end; + // Create reference and insert into current tree + With CreateElement(metPartial,currParent,Current) do + begin + AddChild(Partial); + Data:=aName; + if isWhitespace and assigned(WhiteSpaceEl) then + Prefix:=GetEndingWhiteSpace(WhiteSpaceEl); + end; + if IsWhiteSpace then + FinishWhiteSpace(False); + end; + '/' : + begin + IsWhiteSpace:=CheckWhiteSpace; + if Not (CurrParent.ElementType in [metSection,metInvertedSection]) then + Raise EMustache.CreateFmt(SErrNoSectionToClose,[aName,Current]) + else if (CurrParent.Data<>Trim(aName)) then + Raise EMustache.CreateFmt(SErrSectionClose,[currParent.Data,CurrParent.Position,aName,Current]) + else + currParent:=currParent.Parent; + if IsWhiteSpace then + FinishWhiteSpace; + end + else + CreateDefault(CurrParent,Current,aName); + end; + Current:=NewPos+clStop; + end; + end; + if CurrParent<>aParent then + Raise EMustache.CreateFmt(SErrNotClosedSection,[currParent.Data,CurrParent.Position]) + +end; + +function TMustacheParser.Parse: TMustacheElement; + +begin + Result:=TMustacheParentElement.Create(metRoot,Nil,1); + try + Parse(Result); + except + Result.Free; + Raise; + end; +end; + +{ TMustacheNamedElement } + +procedure TMustacheNamedElement.SetData(Const aData: TMustacheString); + +begin + FName:=Trim(aData); +end; + +function TMustacheNamedElement.GetData: TMustacheString; +begin + Result:=FName; +end; + +{ TMustacheParentElement } + +function TMustacheParentElement.GetElement(aIndex : Integer): TMustacheElement; +begin + If (aIndex<0) or (aIndex>=FCount) then + Raise EMustache.CreateFmt(SErrInvalidIndex,[ClassName,aIndex,FCount-1]); + Result:=FChildren[aIndex]; +end; + +function TMustacheParentElement.GetCount: Integer; +begin + Result:=FCount; +end; + +destructor TMustacheParentElement.Destroy; +begin + While FCount>0 do + begin + Dec(FCount); + FreeAndNil(FChildren[FCount]); + end; + inherited Destroy; +end; + + +procedure TMustacheParentElement.AddChild(aChild: TMustacheElement); + +Var + Len : Integer; + +begin + Len:=Length(FChildren); + if (FCount>=Len) then + SetLength(FChildren,Len+ListGrowCount); + FChildren[FCount]:=aChild; + Inc(FCount); +end; + +procedure TMustacheParentElement.Render(aContext: TMustacheContext; + aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False); + +Var + I : integer; + +begin + For I:=0 to ChildCount-1 do + Children[I].Render(aContext,aOutPut,aPrefix,I=ChildCount-1); +end; + +{ TMustacheElement } + +function TMustacheElement.GetCount: Integer; +begin + Result:=0; +end; + +function TMustacheElement.GetElement(aIndex : Integer): TMustacheElement; +begin + Result:=Nil; +end; + +function TMustacheElement.GetPrefix: TMustacheString; +begin + Result:=''; +end; + +procedure TMustacheElement.SetPrefix(aValue: TMustacheString); +begin + // +end; + +procedure TMustacheElement.Dump(aList: Tstrings; aIndent: TMustacheString; aDumpChildren : Boolean = true); + +Var + I : Integer; + +begin + aList.Add(aIndent+Format('%s (%s, %d) : "%s"',[ClassName,GetEnumName(TypeInfo(TMustacheElementType),Ord(ElementType)),Position,Data])); + if aDumpChildren then + For I:=0 to ChildCount-1 do + Children[I].Dump(aList,' '+aIndent); +end; + +constructor TMustacheElement.Create(aType : TMustacheElementType; aParent : TMustacheElement;aPosition: Integer); +begin + FType:=aType; + FParent:=aParent; + FPosition:=aPosition; +end; + +procedure TMustacheElement.AddChild(aChild: TMustacheElement); +begin + Raise EMustache.CreateFmt(SErrNoChildForElement,[ClassName]) +end; + +{ TMustacheStringOutput } + +procedure TMustacheStringOutput.Output(const aText: TMustacheString); +begin + FData:=FData+aText; +{$IFDEF DEBUGMUSTACHE} + Writeln('--'); + Writeln('Output -]',aText,'[-'); + Writeln('--'); +{$ENDIF} +end; + +procedure TMustacheStringOutput.Reset; +begin + FData:=''; +end; + +begin + TMustacheParser.SetDefaultTypeClass(metRoot,TMustacheParentElement); + TMustacheParser.SetDefaultTypeClass(metComment,TMustacheTextElement); + TMustacheParser.SetDefaultTypeClass(metText,TMustacheTextElement); + TMustacheParser.SetDefaultTypeClass(metVariable,TMustacheVariableElement); + TMustacheParser.SetDefaultTypeClass(metSection,TMustacheSectionElement); + TMustacheParser.SetDefaultTypeClass(metInvertedSection,TMustacheSectionElement); + TMustacheParser.SetDefaultTypeClass(metPartial,TMustachePartialElement); +end. + diff --git a/packages/fcl-mustache/tests/spec/comments.json b/packages/fcl-mustache/tests/spec/comments.json new file mode 100644 index 0000000000..30cb927e62 --- /dev/null +++ b/packages/fcl-mustache/tests/spec/comments.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Comment tags represent content that should never appear in the resulting\noutput.\n\nThe tag's content may contain any substring (including newlines) EXCEPT the\nclosing delimiter.\n\nComment tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Inline","data":{},"expected":"1234567890","template":"12345{{! Comment Block! }}67890","desc":"Comment blocks should be removed from the template."},{"name":"Multiline","data":{},"expected":"1234567890\n","template":"12345{{!\n This is a\n multi-line comment...\n}}67890\n","desc":"Multiline comments should be permitted."},{"name":"Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{! Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{! Indented Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{! Standalone Comment }}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"!","template":" {{! I'm Still Standalone }}\n!","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"!\n","template":"!\n {{! I'm Still Standalone }}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Inline","data":{},"expected":" 12 \n","template":" 12 {{! 34 }}\n","desc":"Inline comments should not strip whitespace"},{"name":"Surrounding Whitespace","data":{},"expected":"12345 67890","template":"12345 {{! Comment Block! }} 67890","desc":"Comment removal should preserve surrounding whitespace."}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/spec/delimiters.json b/packages/fcl-mustache/tests/spec/delimiters.json new file mode 100644 index 0000000000..fcf95888db --- /dev/null +++ b/packages/fcl-mustache/tests/spec/delimiters.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Set Delimiter tags are used to change the tag delimiters for all content\nfollowing the tag in the current compilation unit.\n\nThe tag's content MUST be any two non-whitespace sequences (separated by\nwhitespace) EXCEPT an equals sign ('=') followed by the current closing\ndelimiter.\n\nSet Delimiter tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Pair Behavior","data":{"text":"Hey!"},"expected":"(Hey!)","template":"{{=<% %>=}}(<%text%>)","desc":"The equals sign (used on both sides) should permit delimiter changes."},{"name":"Special Characters","data":{"text":"It worked!"},"expected":"(It worked!)","template":"({{=[ ]=}}[text])","desc":"Characters with special meaning regexen should be valid delimiters."},{"name":"Sections","data":{"section":true,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside sections should persist."},{"name":"Inverted Sections","data":{"section":false,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside inverted sections should persist."},{"name":"Partial Inheritence","data":{"value":"yes"},"expected":"[ .yes. ]\n[ .yes. ]\n","template":"[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n","desc":"Delimiters set in a parent template should not affect a partial.","partials":{"include":".{{value}}."}},{"name":"Post-Partial Behavior","data":{"value":"yes"},"expected":"[ .yes. .yes. ]\n[ .yes. .|value|. ]\n","template":"[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n","desc":"Delimiters set in a partial should not affect the parent template.","partials":{"include":".{{value}}. {{= | | =}} .|value|."}},{"name":"Surrounding Whitespace","data":{},"expected":"| |","template":"| {{=@ @=}} |","desc":"Surrounding whitespace should be left untouched."},{"name":"Outlying Whitespace (Inline)","data":{},"expected":" | \n","template":" | {{=@ @=}}\n","desc":"Whitespace should be left untouched."},{"name":"Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{=@ @=}}\nEnd.\n","desc":"Standalone lines should be removed from the template."},{"name":"Indented Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{=@ @=}}\nEnd.\n","desc":"Indented standalone lines should be removed from the template."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{= @ @ =}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"=","template":" {{=@ @=}}\n=","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"=\n","template":"=\n {{=@ @=}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Pair with Padding","data":{},"expected":"||","template":"|{{= @ @ =}}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/spec/interpolation.json b/packages/fcl-mustache/tests/spec/interpolation.json new file mode 100644 index 0000000000..d1a1a32897 --- /dev/null +++ b/packages/fcl-mustache/tests/spec/interpolation.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Interpolation tags are used to integrate dynamic content into the template.\n\nThe tag's content MUST be a non-whitespace character sequence NOT containing\nthe current closing delimiter.\n\nThis tag's content names the data to replace the tag. A single period (`.`)\nindicates that the item currently sitting atop the context stack should be\nused; otherwise, name resolution is as follows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object, the data is the value returned by the\n method with the given name.\n 5) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nData should be coerced into a string (and escaped, if appropriate) before\ninterpolation.\n\nThe Interpolation tags MUST NOT be treated as standalone.\n","tests":[{"name":"No Interpolation","data":{},"expected":"Hello from {Mustache}!\n","template":"Hello from {Mustache}!\n","desc":"Mustache-free templates should render as-is."},{"name":"Basic Interpolation","data":{"subject":"world"},"expected":"Hello, world!\n","template":"Hello, {{subject}}!\n","desc":"Unadorned tags should interpolate content into the template."},{"name":"HTML Escaping","data":{"forbidden":"& \" < >"},"expected":"These characters should be HTML escaped: & " < >\n","template":"These characters should be HTML escaped: {{forbidden}}\n","desc":"Basic interpolation should be HTML escaped."},{"name":"Triple Mustache","data":{"forbidden":"& \" < >"},"expected":"These characters should not be HTML escaped: & \" < >\n","template":"These characters should not be HTML escaped: {{{forbidden}}}\n","desc":"Triple mustaches should interpolate without HTML escaping."},{"name":"Ampersand","data":{"forbidden":"& \" < >"},"expected":"These characters should not be HTML escaped: & \" < >\n","template":"These characters should not be HTML escaped: {{&forbidden}}\n","desc":"Ampersand should interpolate without HTML escaping."},{"name":"Basic Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{mph}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Triple Mustache Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{{mph}}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Ampersand Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{&mph}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Basic Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{power}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Triple Mustache Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{{power}}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Ampersand Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{&power}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Basic Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{cannot}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Triple Mustache Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{{cannot}}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Ampersand Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{&cannot}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Dotted Names - Basic Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{person.name}}\" == \"{{#person}}{{name}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Triple Mustache Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{{person.name}}}\" == \"{{#person}}{{{name}}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Ampersand Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{&person.name}}\" == \"{{#person}}{{&name}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Arbitrary Depth","data":{"a":{"b":{"c":{"d":{"e":{"name":"Phil"}}}}}},"expected":"\"Phil\" == \"Phil\"","template":"\"{{a.b.c.d.e.name}}\" == \"Phil\"","desc":"Dotted names should be functional to any level of nesting."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"\" == \"\"","template":"\"{{a.b.c}}\" == \"\"","desc":"Any falsey value prior to the last part of the name should yield ''."},{"name":"Dotted Names - Broken Chain Resolution","data":{"a":{"b":{}},"c":{"name":"Jim"}},"expected":"\"\" == \"\"","template":"\"{{a.b.c.name}}\" == \"\"","desc":"Each part of a dotted name should resolve only against its parent."},{"name":"Dotted Names - Initial Resolution","data":{"a":{"b":{"c":{"d":{"e":{"name":"Phil"}}}}},"b":{"c":{"d":{"e":{"name":"Wrong"}}}}},"expected":"\"Phil\" == \"Phil\"","template":"\"{{#a}}{{b.c.d.e.name}}{{/a}}\" == \"Phil\"","desc":"The first part of a dotted name should resolve as any other name."},{"name":"Interpolation - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{string}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Triple Mustache - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{{string}}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Ampersand - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{&string}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Interpolation - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{string}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Triple Mustache - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{{string}}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Ampersand - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{&string}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Interpolation With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{ string }}|","desc":"Superfluous in-tag whitespace should be ignored."},{"name":"Triple Mustache With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{{ string }}}|","desc":"Superfluous in-tag whitespace should be ignored."},{"name":"Ampersand With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{& string }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/spec/inverted.json b/packages/fcl-mustache/tests/spec/inverted.json new file mode 100644 index 0000000000..c9b550b964 --- /dev/null +++ b/packages/fcl-mustache/tests/spec/inverted.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Inverted Section tags and End Section tags are used in combination to wrap a\nsection of the template.\n\nThese tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter; each Inverted Section tag MUST be\nfollowed by an End Section tag with the same content within the same\nsection.\n\nThis tag's content names the data to replace the tag. Name resolution is as\nfollows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object and the method with the given name has an\n arity of 1, the method SHOULD be called with a String containing the\n unprocessed contents of the sections; the data is the value returned.\n 5) Otherwise, the data is the value returned by calling the method with\n the given name.\n 6) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nIf the data is not of a list type, it is coerced into a list as follows: if\nthe data is truthy (e.g. `!!data == true`), use a single-element list\ncontaining the data, otherwise use an empty list.\n\nThis section MUST NOT be rendered unless the data list is empty.\n\nInverted Section and End Section tags SHOULD be treated as standalone when\nappropriate.\n","tests":[{"name":"Falsey","data":{"boolean":false},"expected":"\"This should be rendered.\"","template":"\"{{^boolean}}This should be rendered.{{/boolean}}\"","desc":"Falsey sections should have their contents rendered."},{"name":"Truthy","data":{"boolean":true},"expected":"\"\"","template":"\"{{^boolean}}This should not be rendered.{{/boolean}}\"","desc":"Truthy sections should have their contents omitted."},{"name":"Context","data":{"context":{"name":"Joe"}},"expected":"\"\"","template":"\"{{^context}}Hi {{name}}.{{/context}}\"","desc":"Objects and hashes should behave like truthy values."},{"name":"List","data":{"list":[{"n":1},{"n":2},{"n":3}]},"expected":"\"\"","template":"\"{{^list}}{{n}}{{/list}}\"","desc":"Lists should behave like truthy values."},{"name":"Empty List","data":{"list":[]},"expected":"\"Yay lists!\"","template":"\"{{^list}}Yay lists!{{/list}}\"","desc":"Empty lists should behave like falsey values."},{"name":"Doubled","data":{"two":"second","bool":false},"expected":"* first\n* second\n* third\n","template":"{{^bool}}\n* first\n{{/bool}}\n* {{two}}\n{{^bool}}\n* third\n{{/bool}}\n","desc":"Multiple inverted sections per template should be permitted."},{"name":"Nested (Falsey)","data":{"bool":false},"expected":"| A B C D E |","template":"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested falsey sections should have their contents rendered."},{"name":"Nested (Truthy)","data":{"bool":true},"expected":"| A E |","template":"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested truthy sections should be omitted."},{"name":"Context Misses","data":{},"expected":"[Cannot find key 'missing'!]","template":"[{{^missing}}Cannot find key 'missing'!{{/missing}}]","desc":"Failed context lookups should be considered falsey."},{"name":"Dotted Names - Truthy","data":{"a":{"b":{"c":true}}},"expected":"\"\" == \"\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"\"","desc":"Dotted names should be valid for Inverted Section tags."},{"name":"Dotted Names - Falsey","data":{"a":{"b":{"c":false}}},"expected":"\"Not Here\" == \"Not Here\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"","desc":"Dotted names should be valid for Inverted Section tags."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"Not Here\" == \"Not Here\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"","desc":"Dotted names that cannot be resolved should be considered falsey."},{"name":"Surrounding Whitespace","data":{"boolean":false},"expected":" | \t|\t | \n","template":" | {{^boolean}}\t|\t{{/boolean}} | \n","desc":"Inverted sections should not alter surrounding whitespace."},{"name":"Internal Whitespace","data":{"boolean":false},"expected":" | \n | \n","template":" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n","desc":"Inverted should not alter internal whitespace."},{"name":"Indented Inline Sections","data":{"boolean":false},"expected":" NO\n WAY\n","template":" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n","desc":"Single-line sections should not alter surrounding whitespace."},{"name":"Standalone Lines","data":{"boolean":false},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n","desc":"Standalone lines should be removed from the template."},{"name":"Standalone Indented Lines","data":{"boolean":false},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n {{^boolean}}\n|\n {{/boolean}}\n| A Line\n","desc":"Standalone indented lines should be removed from the template."},{"name":"Standalone Line Endings","data":{"boolean":false},"expected":"|\r\n|","template":"|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{"boolean":false},"expected":"^\n/","template":" {{^boolean}}\n^{{/boolean}}\n/","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{"boolean":false},"expected":"^\n/\n","template":"^{{^boolean}}\n/\n {{/boolean}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Padding","data":{"boolean":false},"expected":"|=|","template":"|{{^ boolean }}={{/ boolean }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/spec/partials.json b/packages/fcl-mustache/tests/spec/partials.json new file mode 100644 index 0000000000..e5f21a2a48 --- /dev/null +++ b/packages/fcl-mustache/tests/spec/partials.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Partial tags are used to expand an external template into the current\ntemplate.\n\nThe tag's content MUST be a non-whitespace character sequence NOT containing\nthe current closing delimiter.\n\nThis tag's content names the partial to inject. Set Delimiter tags MUST NOT\naffect the parsing of a partial. The partial MUST be rendered against the\ncontext stack local to the tag. If the named partial cannot be found, the\nempty string SHOULD be used instead, as in interpolations.\n\nPartial tags SHOULD be treated as standalone when appropriate. If this tag\nis used standalone, any whitespace preceding the tag should treated as\nindentation, and prepended to each line of the partial before rendering.\n","tests":[{"name":"Basic Behavior","data":{},"expected":"\"from partial\"","template":"\"{{>text}}\"","desc":"The greater-than operator should expand to the named partial.","partials":{"text":"from partial"}},{"name":"Failed Lookup","data":{},"expected":"\"\"","template":"\"{{>text}}\"","desc":"The empty string should be used when the named partial is not found.","partials":{}},{"name":"Context","data":{"text":"content"},"expected":"\"*content*\"","template":"\"{{>partial}}\"","desc":"The greater-than operator should operate within the current context.","partials":{"partial":"*{{text}}*"}},{"name":"Recursion","data":{"content":"X","nodes":[{"content":"Y","nodes":[]}]},"expected":"X<Y<>>","template":"{{>node}}","desc":"The greater-than operator should properly recurse.","partials":{"node":"{{content}}<{{#nodes}}{{>node}}{{/nodes}}>"}},{"name":"Surrounding Whitespace","data":{},"expected":"| \t|\t |","template":"| {{>partial}} |","desc":"The greater-than operator should not alter surrounding whitespace.","partials":{"partial":"\t|\t"}},{"name":"Inline Indentation","data":{"data":"|"},"expected":" | >\n>\n","template":" {{data}} {{> partial}}\n","desc":"Whitespace should be left untouched.","partials":{"partial":">\n>"}},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n>|","template":"|\r\n{{>partial}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags.","partials":{"partial":">"}},{"name":"Standalone Without Previous Line","data":{},"expected":" >\n >>","template":" {{>partial}}\n>","desc":"Standalone tags should not require a newline to precede them.","partials":{"partial":">\n>"}},{"name":"Standalone Without Newline","data":{},"expected":">\n >\n >","template":">\n {{>partial}}","desc":"Standalone tags should not require a newline to follow them.","partials":{"partial":">\n>"}},{"name":"Standalone Indentation","data":{"content":"<\n->"},"expected":"\\\n |\n <\n->\n |\n/\n","template":"\\\n {{>partial}}\n/\n","desc":"Each line of the partial should be indented before rendering.","partials":{"partial":"|\n{{{content}}}\n|\n"}},{"name":"Padding Whitespace","data":{"boolean":true},"expected":"|[]|","template":"|{{> partial }}|","desc":"Superfluous in-tag whitespace should be ignored.","partials":{"partial":"[]"}}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/spec/sections.json b/packages/fcl-mustache/tests/spec/sections.json new file mode 100644 index 0000000000..795f6acd74 --- /dev/null +++ b/packages/fcl-mustache/tests/spec/sections.json @@ -0,0 +1 @@ +{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Section tags and End Section tags are used in combination to wrap a section\nof the template for iteration\n\nThese tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter; each Section tag MUST be followed\nby an End Section tag with the same content within the same section.\n\nThis tag's content names the data to replace the tag. Name resolution is as\nfollows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object and the method with the given name has an\n arity of 1, the method SHOULD be called with a String containing the\n unprocessed contents of the sections; the data is the value returned.\n 5) Otherwise, the data is the value returned by calling the method with\n the given name.\n 6) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nIf the data is not of a list type, it is coerced into a list as follows: if\nthe data is truthy (e.g. `!!data == true`), use a single-element list\ncontaining the data, otherwise use an empty list.\n\nFor each element in the data list, the element MUST be pushed onto the\ncontext stack, the section MUST be rendered, and the element MUST be popped\noff the context stack.\n\nSection and End Section tags SHOULD be treated as standalone when\nappropriate.\n","tests":[{"name":"Truthy","data":{"boolean":true},"expected":"\"This should be rendered.\"","template":"\"{{#boolean}}This should be rendered.{{/boolean}}\"","desc":"Truthy sections should have their contents rendered."},{"name":"Falsey","data":{"boolean":false},"expected":"\"\"","template":"\"{{#boolean}}This should not be rendered.{{/boolean}}\"","desc":"Falsey sections should have their contents omitted."},{"name":"Context","data":{"context":{"name":"Joe"}},"expected":"\"Hi Joe.\"","template":"\"{{#context}}Hi {{name}}.{{/context}}\"","desc":"Objects and hashes should be pushed onto the context stack."},{"name":"Deeply Nested Contexts","data":{"a":{"one":1},"b":{"two":2},"c":{"three":3},"d":{"four":4},"e":{"five":5}},"expected":"1\n121\n12321\n1234321\n123454321\n1234321\n12321\n121\n1\n","template":"{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{#e}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}\n{{/e}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n","desc":"All elements on the context stack should be accessible."},{"name":"List","data":{"list":[{"item":1},{"item":2},{"item":3}]},"expected":"\"123\"","template":"\"{{#list}}{{item}}{{/list}}\"","desc":"Lists should be iterated; list items should visit the context stack."},{"name":"Empty List","data":{"list":[]},"expected":"\"\"","template":"\"{{#list}}Yay lists!{{/list}}\"","desc":"Empty lists should behave like falsey values."},{"name":"Doubled","data":{"two":"second","bool":true},"expected":"* first\n* second\n* third\n","template":"{{#bool}}\n* first\n{{/bool}}\n* {{two}}\n{{#bool}}\n* third\n{{/bool}}\n","desc":"Multiple sections per template should be permitted."},{"name":"Nested (Truthy)","data":{"bool":true},"expected":"| A B C D E |","template":"| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested truthy sections should have their contents rendered."},{"name":"Nested (Falsey)","data":{"bool":false},"expected":"| A E |","template":"| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested falsey sections should be omitted."},{"name":"Context Misses","data":{},"expected":"[]","template":"[{{#missing}}Found key 'missing'!{{/missing}}]","desc":"Failed context lookups should be considered falsey."},{"name":"Implicit Iterator - String","data":{"list":["a","b","c","d","e"]},"expected":"\"(a)(b)(c)(d)(e)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should directly interpolate strings."},{"name":"Implicit Iterator - Integer","data":{"list":[1,2,3,4,5]},"expected":"\"(1)(2)(3)(4)(5)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should cast integers to strings and interpolate."},{"name":"Implicit Iterator - Decimal","data":{"list":[1.1,2.2,3.3,4.4,5.5]},"expected":"\"(1.1)(2.2)(3.3)(4.4)(5.5)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should cast decimals to strings and interpolate."},{"name":"Implicit Iterator - Array","desc":"Implicit iterators should allow iterating over nested arrays.","data":{"list":[[1,2,3],["a","b","c"]]},"template":"\"{{#list}}({{#.}}{{.}}{{/.}}){{/list}}\"","expected":"\"(123)(abc)\""},{"name":"Dotted Names - Truthy","data":{"a":{"b":{"c":true}}},"expected":"\"Here\" == \"Here\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"Here\"","desc":"Dotted names should be valid for Section tags."},{"name":"Dotted Names - Falsey","data":{"a":{"b":{"c":false}}},"expected":"\"\" == \"\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"","desc":"Dotted names should be valid for Section tags."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"\" == \"\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"","desc":"Dotted names that cannot be resolved should be considered falsey."},{"name":"Surrounding Whitespace","data":{"boolean":true},"expected":" | \t|\t | \n","template":" | {{#boolean}}\t|\t{{/boolean}} | \n","desc":"Sections should not alter surrounding whitespace."},{"name":"Internal Whitespace","data":{"boolean":true},"expected":" | \n | \n","template":" | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n","desc":"Sections should not alter internal whitespace."},{"name":"Indented Inline Sections","data":{"boolean":true},"expected":" YES\n GOOD\n","template":" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n","desc":"Single-line sections should not alter surrounding whitespace."},{"name":"Standalone Lines","data":{"boolean":true},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n","desc":"Standalone lines should be removed from the template."},{"name":"Indented Standalone Lines","data":{"boolean":true},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n {{#boolean}}\n|\n {{/boolean}}\n| A Line\n","desc":"Indented standalone lines should be removed from the template."},{"name":"Standalone Line Endings","data":{"boolean":true},"expected":"|\r\n|","template":"|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{"boolean":true},"expected":"#\n/","template":" {{#boolean}}\n#{{/boolean}}\n/","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{"boolean":true},"expected":"#\n/\n","template":"#{{#boolean}}\n/\n {{/boolean}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Padding","data":{"boolean":true},"expected":"|=|","template":"|{{# boolean }}={{/ boolean }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/packages/fcl-mustache/tests/tcbasemustache.pas b/packages/fcl-mustache/tests/tcbasemustache.pas new file mode 100644 index 0000000000..80abdf9e37 --- /dev/null +++ b/packages/fcl-mustache/tests/tcbasemustache.pas @@ -0,0 +1,290 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + Helper classes for Mustache test cases + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit tcbasemustache; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, fpmustache; + +type + + { TTestContext } + + (* StringList with following encoding + // Null value + aName=<null> + // false value + aName=<null> + // plain value + aName=AValue + // Object value & member. Object value must be present + SubObj={} + SubObj.aName=aValue + // Array and members. Array value must be present + SubObj.SubArr=[] + SubObj.SubArr[0]={} + SubObj.SubArr[0].aName=aValue + SubObj.SubArr[1]={} + Subobj.SubArr[1].aName=aValue + *) + + TTestContext = class (TMustacheContext) + Private + FValues : TStringList; + FPath : String; + public + Constructor Create(aCallback: TGetTextValueEvent); override; + Destructor destroy; override; + Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override; + Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override; + Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override; + Procedure PopSection(Const aName : TMustacheString); override; + Procedure SetValue(const aPath,aValue : string); + Property Values : TStringList read FValues; + end; + + TBaseMustacheTest = class(TTestCase) + Private + FPartials: TStrings; + FTemplate: String; + FResult: TMustacheElement; + FParser: TMustacheParser; + Protected + Function CreateParser : TMustacheParser; virtual; abstract; + Procedure DoGetPartial(const aName: TMustacheString; var aHandled: Boolean; var aValue: TMustacheString); + Public + Class Procedure AssertEquals(Msg : String; aExpected,aActual : TMustacheElementType); overload; + Class Function AssertElement(aParent : TMustacheElement; aIndex: Integer; aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil) : TMustacheElement; overload; + Function AssertElement(aIndex: Integer; aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil) : TMustacheElement; overload; + Procedure AssertResultCount(aCount : Integer); + procedure SetUp; override; + procedure TearDown; override; + Procedure CallParser; + Procedure AddPartial(Const aName,aText: TMustacheString); + Property Partials : TStrings Read FPartials; + Property Template : String Read FTemplate Write FTemplate; + property ParseResult : TMustacheElement Read FResult; + property Parser : TMustacheParser Read FParser; + end; + + +implementation + +uses strutils, typinfo; + +{ TTestContext } + +constructor TTestContext.Create(aCallback: TGetTextValueEvent); +begin + inherited Create(aCallback); + FValues:=TStringList.Create; + FValues.OwnsObjects:=True; +end; + +destructor TTestContext.destroy; +begin + FreeAndNil(FValues); + inherited destroy; +end; + +function TTestContext.GetTextValue(const aName: TMustacheString + ): TMustacheString; + +Var + aPath,N : String; + Done : Boolean; +begin + Result:=''; + aPath:=FPath; + Done:=False; + Repeat + if aPath<>'' then + N:=aPath+'.'+aName + else + begin + N:=aName; + Done:=True; + end; + Result:=FValues.Values[N]; + if not Done then + aPath:=Copy(aPath,1,RPos('.',aPath)-1); + until (Result<>'') or Done; +end; + +function TTestContext.MoveNextSectionItem(const aName: TMustacheString + ): Boolean; + +Var + L,P,Idx : Integer; + N : String; + +begin + L:=Length(FPath); + if (L>0) and (FPath[L]=']') then + begin + P:=RPos('[',FPath)+1; + Idx:=StrToIntDef(Copy(FPath,P,L-P),-1); + N:=Copy(FPath,1,P-1)+IntToStr(Idx+1)+']'; + Result:=FValues.Values[N]<>''; // We could check for {} + if Result then + FPath:=N; + end; + +end; + +function TTestContext.PushSection(const aName: TMustacheString): TMustacheSectionType; + +Var + aPath,S : String; + +begin + if FPath<>'' then + FPath:=FPath+'.'; + aPath:=FPath+aName; + S:=Values.Values[aPath]; + if S='{}' then + begin + FPath:=aPath; + result:=mstSingle; + end; + if S='[]' then + begin + if Values.Values[aPath+'[0]']='' then + Result:=mstNone + else + begin + FPath:=aPath+'[-1]'; + result:=mstList; + end; + end + else if (s='<null>') or (s='<false>') or (s='') then + begin + Result:=mstNone; + end + else + begin + FPath:=aPath; + result:=mstSingle; + end; + +end; + +procedure TTestContext.PopSection(const aName: TMustacheString); +begin + FPath:=Copy(FPath,1,RPos('.',FPath)-1); +end; + +procedure TTestContext.SetValue(const aPath, aValue: string); +begin + Values.Values[aPath]:=aValue; +end; + + +{ TBaseMustacheTest } + +procedure TBaseMustacheTest.SetUp; + +begin + Inherited; + FParser:=CreateParser; + FParser.Partials:=TMustachePartialList.Create(metRoot,Nil,0); + FParser.OnGetPartial:=@DoGetPartial; + FPartials:=TStringList.Create; + TStringList(FPartials).OwnsObjects:=True; +end; + +procedure TBaseMustacheTest.TearDown; + +begin + FreeAndNil(FPartials); + FreeAndNil(FResult); + FParser.Partials.Free; + FreeAndNil(FParser); + Inherited; +end; + +procedure TBaseMustacheTest.DoGetPartial(const aName: TMustacheString; + var aHandled: Boolean; var aValue: TMustacheString); +begin + aValue:=FPartials.Values[aName]; + aHandled:=FPartials.IndexOfName(aName)<>-1; +end; + +class function TBaseMustacheTest.AssertElement(aParent: TMustacheElement; + aIndex: Integer; aType: TMustacheElementType; aData: String; + aClass: TMustacheElementClass): TMustacheElement; +Var + El : TMustacheElement; + aChild : String; +begin + AssertNotNull('Have parent',aParent); + AssertTrue(Format('Index %d in range 0..%d',[aIndex,aParent.ChildCount-1]),(aIndex>=0) and (aIndex<aParent.ChildCount)); + EL:=aParent.Children[aIndex]; + aChild:=Format('Child %d',[aIndex]); + AssertNotNull('Have result '+aChild,El); + AssertEquals(aChild+' has correct type',aType,El.ElementType); + AssertEquals(aChild+' has correct data',aData,El.Data); + if (aClass<>Nil) then + AssertEquals(aChild+' has correct class',aClass,el.Classtype); + Result:=El; +end; + +function TBaseMustacheTest.AssertElement(aIndex: Integer; + aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil): TMustacheElement; + +begin + AssertNotNull('Have result',FResult); + Result:=AssertElement(FResult,aIndex,aType,aData,aClass); +end; + +procedure TBaseMustacheTest.AssertResultCount(aCount: Integer); +begin + AssertNotNull('Have result',FResult); + AssertEquals('Result count',aCount,FResult.ChildCount); +end; + + +procedure TBaseMustacheTest.CallParser; + +begin + Parser.Template:=Template; + FResult:=Parser.Parse; +end; + +procedure TBaseMustacheTest.AddPartial(const aName, aText: TMustacheString); + +//Var +// T : TMustacheTextElement; + +begin +// T:=TMustacheTextElement.Create(metText,Nil,0); +// T.Data:=aText; + FPartials.Add(aName+'='+atext); +end; + +class procedure TBaseMustacheTest.AssertEquals(Msg: String; aExpected, + aActual: TMustacheElementType); + +begin + AssertEquals(Msg,GetEnumName(typeInfo(TMustacheElementType),Ord(aExpected)), + GetEnumName(typeInfo(TMustacheElementType),Ord(aActual))); +end; + + +end. + diff --git a/packages/fcl-mustache/tests/tcdbmustache.pas b/packages/fcl-mustache/tests/tcdbmustache.pas new file mode 100644 index 0000000000..07710c9493 --- /dev/null +++ b/packages/fcl-mustache/tests/tcdbmustache.pas @@ -0,0 +1,149 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + Test cases for DB Context for Mustache + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit tcdbmustache; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, testregistry, fpmustache, db, bufdataset, fpdbmustache; + +Type + + { TTestMustacheDBContext } + + TTestMustacheDBContext = Class(TTestCase) + private + FContext: TMustacheDBContext; + FDataset1: TBufDataset; + FDataset2: TBufDataset; + FMustache: TMustache; + Public + Procedure Setup; override; + Procedure TearDown; override; + Procedure CreateDataset1; + Procedure CreateDataset2; + Property Dataset1 : TBufDataset Read FDataset1; + Property Dataset2 : TBufDataset Read FDataset2; + Property Context : TMustacheDBContext Read FContext; + Property Mustache : TMustache Read FMustache; + Published + Procedure TestEmpty; + Procedure TestSingleSection; + Procedure TestTwoSections; + end; + +implementation + +Const + Template1 = '{{title}}! {{#Parents}}{{name}} {{age}} - {{/Parents}}'; + Template2 = '{{title}}! {{#Parents}}{{name}}({{age}}) : {{#Children}}{{name}} {{age}},{{/Children}} - {{/Parents}}'; + +{ TTestMustacheDBContext } + +procedure TTestMustacheDBContext.Setup; +begin + Inherited; + FDataset1:=TBufDataset.Create(Nil); + FDataset1.Name:='Parents'; + FDataset2:=TBufDataset.Create(Nil); + FDataset2.Name:='Children'; + FContext:=TMustacheDBContext.Create(Nil); + FContext.StaticValues.Values['title']:='Family'; + FMustache:=TMustache.Create(Nil); +end; + +procedure TTestMustacheDBContext.TearDown; +begin + FreeAndNil(FDataset1); + FreeAndNil(FDataset2); + FreeAndNil(FContext); + FreeAndNil(FMustache); +end; + +procedure TTestMustacheDBContext.CreateDataset1; +begin + FDataset1.FieldDefs.Add('name',ftString,20); + FDataset1.FieldDefs.Add('age',ftInteger); + FDataset1.CreateDataset; + FDataset1.Append; + FDataset1.FieldByName('name').AsString:='Father'; + FDataset1.FieldByName('age').AsInteger:=40; + FDataset1.Post; + FDataset1.Append; + FDataset1.FieldByName('name').AsString:='Mother'; + FDataset1.FieldByName('age').AsInteger:=39; + FDataset1.Post; + FDataset1.First; +end; + +procedure TTestMustacheDBContext.CreateDataset2; +begin + FDataset2.FieldDefs.Add('name',ftString,20); + FDataset2.FieldDefs.Add('age',ftInteger); + FDataset2.CreateDataset; + FDataset2.Append; + FDataset2.FieldByName('name').AsString:='Child1'; + FDataset2.FieldByName('age').AsInteger:=4; + FDataset2.Post; + FDataset2.Append; + FDataset2.FieldByName('name').AsString:='Child2'; + FDataset2.FieldByName('age').AsInteger:=2; + FDataset2.Post; + FDataset2.First; +end; + +procedure TTestMustacheDBContext.TestEmpty; +begin + AssertNotNull('Mustache',Mustache); + AssertNotNull('Dataset1',Dataset1); + AssertNotNull('Dataset2',Dataset2); + AssertNotNull('Context',Context); + AssertEquals('Context static','Family',Context.StaticValues.Values['title']); +end; + +procedure TTestMustacheDBContext.TestSingleSection; + +Var + S : String; + +begin + Mustache.Template:=Template1; + CreateDataset1; + Context.AddDataset(FDataset1); + S:=Mustache.Render(Context); + AssertEquals('Correct result','Family! Father 40 - Mother 39 - ',S); +end; + +procedure TTestMustacheDBContext.TestTwoSections; + +Var + S : String; + +begin + Mustache.Template:=Template2; + CreateDataset1; + CreateDataset2; + Context.AddDataset(FDataset1); + Context.AddDataset(FDataset2); + S:=Mustache.Render(Context); + AssertEquals('Correct result','Family! Father(40) : Child1 4,Child2 2, - Mother(39) : - ',S); +end; + +initialization + RegisterTest(TTestMustacheDBContext); +end. + diff --git a/packages/fcl-mustache/tests/tcexmustache.pas b/packages/fcl-mustache/tests/tcexmustache.pas new file mode 100644 index 0000000000..b88ed9fba0 --- /dev/null +++ b/packages/fcl-mustache/tests/tcexmustache.pas @@ -0,0 +1,199 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + Test cases for expression parser support + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit tcexmustache; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, fpjson, testregistry, fpmustache, tcbasemustache, fpexmustache, fpexprpars; + +Type + + { TTestExMustacheParser } + + TTestExMustacheParser = Class(TBaseMustacheTest) + private + FExpr: TFPExpressionParser; + FOutput: TMustacheStringOutput; + FContext : TMustacheJSONContext; + FData : TJSONData; + procedure GetVar(var Result: TFPExpressionResult; ConstRef + AName: ShortString); + Public + Procedure SetUp; override; + Procedure TearDown; override; + Function CreateParser: TMustacheParser; override; + Property Expr : TFPExpressionParser Read FExpr; + Property Output : TMustacheStringOutput Read FOutput; + Published + Procedure TestSimple; + Procedure TestRenderSimple; + Procedure TestRenderSection; + end; + + { TTestMustacheExpr } + + TTestMustacheExpr = Class(TTestCase) + private + FJSON: TJSONObject; + FMustache: TMustacheExpr; + public + Procedure SetUp; override; + Procedure TearDown; override; + Property Mustache : TMustacheExpr Read FMustache; + Property JSON : TJSONObject Read FJSON; + Published + Procedure TestEmpty; + Procedure TestRegisterVariables; + Procedure TestRenderSection; + procedure TestRenderSectionStaticVariables; + end; + + +implementation + +Const + STestJSON = '{ "data" : [ { "name": "me", "age" : 10}, { "name": "you", "age" : 12 }, { "name": "he", "age" : 13 } ] }'; + +{ TTestMustacheExpr } + +procedure TTestMustacheExpr.SetUp; +begin + inherited SetUp; + FMustache:=TMustacheExpr.Create(Nil); + FJSON:=GetJSON(STestJSON) as TJSONObject; +end; + +procedure TTestMustacheExpr.TearDown; +begin + FreeAndNil(FJSON); + FreeAndNil(FMustache); + inherited TearDown; +end; + +procedure TTestMustacheExpr.TestEmpty; +begin + AssertNotNull('Have mustache instance',Mustache); + AssertNotNull('Have mustache expression engine instance',Mustache.ExpressionParser); +end; + +procedure TTestMustacheExpr.TestRegisterVariables; +begin + Mustache.RegisterVariables(JSON,'data[0]',True); + AssertEquals('Variable count',2,Mustache.ExpressionParser.Identifiers.Count); + AssertEquals('Variable 0','name',Mustache.ExpressionParser.Identifiers[0].Name); + AssertEquals('Variable 1','age',Mustache.ExpressionParser.Identifiers[1].Name); + AssertTrue('Variable 0 type',rtString=Mustache.ExpressionParser.Identifiers[0].ResultType); + AssertTrue('Variable 1 type',rtInteger=Mustache.ExpressionParser.Identifiers[1].ResultType); +end; + +procedure TTestMustacheExpr.TestRenderSection; + +Var + S : String; + +Const + Template = '{{#data}}{{[name]}}:{{[age>11]}} {{/data}}'; + +begin + Mustache.Template:=Template; + Mustache.RegisterVariables(JSON,'data[0]',True); + S:=Mustache.Render(JSON); + AssertEquals('Correct result','me:False you:True he:True ',S); +end; + +procedure TTestMustacheExpr.TestRenderSectionStaticVariables; +Var + S : String; + +Const + Template = '{{#data}}{{[name]}}:{{[age>11]}} {{/data}}'; + +begin + Mustache.Template:=Template; + Mustache.RegisterVariables(JSON,'data[0]',False); + S:=Mustache.Render(JSON); + AssertEquals('Correct result','me:False me:False me:False ',S); +end; + + +{ TTestExMustacheParser } + +procedure TTestExMustacheParser.SetUp; +begin + FExpr:=TFPExpressionParser.Create(Nil); + Foutput:=TMustacheStringOutput.Create; + inherited SetUp; +end; + +procedure TTestExMustacheParser.TearDown; +begin + inherited TearDown; + FreeAndNil(FExpr); + FreeAndNil(Foutput); + FreeAndNil(FContext); + FreeAndNil(FData); +end; + +function TTestExMustacheParser.CreateParser: TMustacheParser; + +Var + P : TMustacheExprParser; + +begin + P:=TMustacheExprParser.Create; + P.ExprParser:=FExpr; + Result:=P; +end; + +procedure TTestExMustacheParser.TestSimple; +begin + Template:='{{[1+2]}}'; + CallParser; + AssertElement(0,metVariable,'1+2',TMustacheExprElement); +end; + +procedure TTestExMustacheParser.TestRenderSimple; +begin + TestSimple; + ParseResult.Children[0].Render(Nil,Output,'',False); + AssertEquals('Correct result','3',Output.Data); +end; + +procedure TTestExMustacheParser.GetVar(Var Result : TFPExpressionResult; ConstRef AName : ShortString); + +begin + Result.ResultType:=rtInteger; + Result.ResInteger:=StrToINt(FContext.GetTextValue('age')); +end; + +procedure TTestExMustacheParser.TestRenderSection; +begin + FData:=GetJSON(STestJSON); + FContext:=TMustacheJSONContext.Create(FData,Nil); + FExpr.Identifiers.AddVariable('age',rtInteger,@GetVar); + Template:='{{#data}}{{{name}}}:{{[age>11]}} {{/data}}'; + CallParser; + ParseResult.Render(FContext,Output,'',False); + AssertEquals('Correct result','me:False you:True he:True ',Output.Data); +end; + +initialization + RegisterTests([TTestExMustacheParser,TTestMustacheExpr]); +end. + diff --git a/packages/fcl-mustache/tests/tcmustache.pas b/packages/fcl-mustache/tests/tcmustache.pas new file mode 100644 index 0000000000..6175044b0b --- /dev/null +++ b/packages/fcl-mustache/tests/tcmustache.pas @@ -0,0 +1,728 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + Test cases for basic mustache parser support + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit tcmustache; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, testregistry, fpmustache, tcbasemustache; + +type + + { TTestMustacheParser } + + + TTestMustacheParser= class(TBaseMustacheTest) + private + protected + Function CreateParser : TMustacheParser; override; + Public + procedure SetUp; override; + procedure TearDown; override; + published + procedure TestEmpty; + procedure TestText; + procedure TestVariable; + procedure TestVariableErrNonClosed; + procedure TestVariableAlternateStartStop; + procedure TestDottedVariable; + procedure TestVariableNoUnescape; + procedure TestVariableNoUnescapeErrNonClosed; + procedure TestVariableNoUnescapeAlternateStartStop; + procedure TestComment; + procedure TestCommentSurround; + procedure TestCommentStandalone; + procedure TestCommentStandaloneSpaced; + procedure TestSetDelimiter; + procedure TestSetDelimiterErrInvalid; + procedure TestSection; + procedure TestSectionNested; + procedure TestSectionErrNotClosed; + procedure TestSectionErrWrongClosed; + procedure TestSectionErrNotStarted; + procedure TestTextSection; + procedure TestPartial; + end; + + { TTestMustacheOutput } + + TTestMustacheOutput = class(TTestCase) + Published + Procedure TestStringOutput; + end; + + { TTestMustacheElement } + + TTestMustacheElement = class(TTestCase) + private + FContext: TTestContext; + FEl: TMustacheElement; + Foutput: TMustacheStringOutput; + procedure DoCallBack(const aName: TMustacheString; var aHandled: Boolean; + var aValue: TMustacheString); + Public + Procedure SetUp; override; + Procedure TearDown; override; + Property Context : TTestContext Read FContext; + Property Output : TMustacheStringOutput Read Foutput; + Property El : TMustacheElement Read FEl; + Published + Procedure TestEmpty; + Procedure TestTextElement; + Procedure TestTextElementNoEscape; + Procedure TestTextElementComment; + Procedure TestTextElementPrefix; + procedure TestTextElementPrefixNotLast; + procedure TestTextElementPrefixLast; + Procedure TestVariableElement; + Procedure TestVariableElementNoEscape; + Procedure TestVariableElementEscape; + Procedure TestSectionEmpty; + Procedure TestSectionValue; + Procedure TestSectionValueFalse; + Procedure TestSectionValueNull; + Procedure TestSectionValueEmptyArray; + Procedure TestSectionValueArray1El; + Procedure TestSectionValueArray2El; + Procedure TestSectionValueArray2ElValue; + Procedure TestSectionValueArray1ElValueSuper; + Procedure TestSectionValueArray2ElValueSuper; + Procedure TestParentElement; + Procedure TestParentElementRender; + Procedure TestParentElementRenderPrefix; + end; + +implementation + +uses Typinfo; + +Const + SNeedsQuoting = '< > & "'; + SQuotedResult = '< > & "'; + + +{ TTestMustacheElement } + +procedure TTestMustacheElement.DoCallBack(const aName: TMustacheString; + var aHandled: Boolean; var aValue: TMustacheString); +begin + aValue:=''; +end; + +procedure TTestMustacheElement.SetUp; +begin + inherited SetUp; + FOutput:=TMustacheStringOutput.Create; + FContext:=TTestContext.Create(@DoCallBack); +end; + +procedure TTestMustacheElement.TearDown; +begin + FreeAndNil(FContext); + FreeAndNil(FOutput); + FreeAndNil(FEl); + inherited TearDown; +end; + +procedure TTestMustacheElement.TestEmpty; +begin + AssertNotNull('Have output',Output); +end; + +procedure TTestMustacheElement.TestTextElement; + +begin + Fel:=TMustacheTextElement.Create(metText,Nil,0); + El.Render(Nil,Output); + AssertEquals('No output','',Output.Data); + El.Data:='me'; + El.Render(Nil,Output); + AssertEquals('Correct output','me',Output.Data); +end; + +procedure TTestMustacheElement.TestTextElementNoEscape; +begin + Fel:=TMustacheTextElement.Create(metText,Nil,0); + El.Data:=SNeedsQuoting; + El.Render(Nil,Output); + AssertEquals('Correct output',SNeedsQuoting,Output.Data); +end; + +procedure TTestMustacheElement.TestTextElementComment; +begin + Fel:=TMustacheTextElement.Create(metComment,Nil,0); + El.Data:='Something'; + El.Render(Nil,Output); + AssertEquals('Correct output','',Output.Data); +end; + +procedure TTestMustacheElement.TestTextElementPrefix; +begin + Fel:=TMustacheTextElement.Create(metText,Nil,0); + El.Data:='me'#10'you'; + El.Render(Nil,Output,' '); + AssertEquals('Correct output 1','me'#10' you',Output.Data); +end; + +procedure TTestMustacheElement.TestTextElementPrefixNotLast; +begin + Fel:=TMustacheTextElement.Create(metText,Nil,0); + El.Data:='me'#10'you'#10; + El.Render(Nil,Output,' '); + AssertEquals('Correct output 2','me'#10' you'#10' ',Output.Data); +end; + +procedure TTestMustacheElement.TestTextElementPrefixLast; + +begin + Fel:=TMustacheTextElement.Create(metText,Nil,0); + El.Data:='me'#10'you'#10; + El.Render(Nil,Output,' ',True); + AssertEquals('Correct output 2','me'#10' you'#10,Output.Data); +end; + + +procedure TTestMustacheElement.TestVariableElement; +begin + Fel:=TMustacheVariableElement.Create(metText,Nil,0); + Context.Values.Values['name']:='abc'; + El.Data:='name'; + El.Render(Context,Output); + AssertEquals('Correct output','abc',Output.Data); +end; + + +procedure TTestMustacheElement.TestVariableElementNoEscape; +begin + Fel:=TMustacheVariableElement.Create(metText,Nil,0); + Context.Values.Values['name']:=SNeedsQuoting; + El.Data:='{name}'; + El.Render(Context,Output); + AssertEquals('Correct output',SNeedsQuoting,Output.Data); +end; + +procedure TTestMustacheElement.TestVariableElementEscape; +begin + Fel:=TMustacheVariableElement.Create(metText,Nil,0); + Context.Values.Values['name']:=SNeedsQuoting; + El.Data:='name'; + El.Render(Context,Output); + AssertEquals('Correct output',SQuotedResult,Output.Data); +end; + +procedure TTestMustacheElement.TestSectionEmpty; + +Var + T : TMustacheTextElement; + +begin + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('No output','',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValue; +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','b'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('Single pass','a',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueFalse; +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','<false>'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('no pass','',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueNull; + +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','<null>'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('no pass','',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueEmptyArray; +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','[]'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('no pass','',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueArray1El; +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','[]'); + Context.SetValue('s[0]','toto'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('Single pass','a',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueArray2El; + +Var + T : TMustacheTextElement; + +begin + Context.SetValue('s','[]'); + Context.SetValue('s[0]','toto'); + Context.SetValue('s[1]','tata'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheTextElement.Create(metText,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('Double pass','aa',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueArray2ElValue; + +Var + T : TMustacheElement; + +begin + Context.SetValue('s','[]'); + Context.SetValue('s[0]','{}'); + Context.SetValue('s[0].a','1'); + Context.SetValue('s[1]','{}'); + Context.SetValue('s[1].a','2'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheVariableElement.Create(metVariable,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('Double pass','12',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueArray1ElValueSuper; + +Var + T : TMustacheElement; + +begin + Context.SetValue('s','[]'); + Context.SetValue('s[0]','{}'); + Context.SetValue('s[0].b','1'); + Context.SetValue('a','2'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheVariableElement.Create(metVariable,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + Fel.Render(Context,Output); + AssertEquals('Single pass','2',Output.Data); +end; + +procedure TTestMustacheElement.TestSectionValueArray2ElValueSuper; +Var + T : TMustacheElement; + +begin + Context.SetValue('s','[]'); + Context.SetValue('s[0]','{}'); + Context.SetValue('s[0].b','1'); + Context.SetValue('s[1]','{}'); + Context.SetValue('s[1].b','2'); + Context.SetValue('a','.a.'); + Fel:=TMustacheSectionElement.Create(metSection,Nil,0); + Fel.Data:='s'; + T:=TMustacheVariableElement.Create(metVariable,Nil,0); + Fel.AddChild(T); + T.Data:='a'; + T:=TMustacheVariableElement.Create(metVariable,Nil,0); + Fel.AddChild(T); + T.Data:='b'; + Fel.Render(Context,Output); + AssertEquals('Single pass','.a.1.a.2',Output.Data); +end; + +procedure TTestMustacheElement.TestParentElement; + +Var + SEl : TMustacheElement; + +begin + Fel:=TMustacheParentElement.Create(metSection,Nil,0); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + AssertSame('Parent stored',Fel,Sel.Parent); + AssertEquals('Not added to parent',0,FEl.ChildCount); + Fel.AddChild(Sel); + AssertEquals('added to parent - count',1,FEl.ChildCount); + AssertSame('added to parent - stored',Sel,FEl.Children[0]); +end; + +procedure TTestMustacheElement.TestParentElementRender; + +Var + SEl : TMustacheElement; + +begin + Fel:=TMustacheParentElement.Create(metSection,Nil,0); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='a'; + Fel.AddChild(Sel); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='b'; + Fel.AddChild(Sel); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='c'; + Fel.AddChild(Sel); + Fel.Render(Context,Output); + AssertEquals('Correct output','abc',Output.Data); +end; + +procedure TTestMustacheElement.TestParentElementRenderPrefix; +Var + SEl : TMustacheElement; + +begin + Fel:=TMustacheParentElement.Create(metSection,Nil,0); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='a'#10'b'; + Fel.AddChild(Sel); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='d'#10'e'; + Fel.AddChild(Sel); + Sel:=TMustacheTextElement.Create(metText,Fel,0); + Sel.Data:='f'#10; + Fel.AddChild(Sel); + Fel.Render(Context,Output,' '); + AssertEquals('Correct output','a'#10' bd'#10' ef'#10,Output.Data); +end; + +{ TTestMustacheOutput } + +procedure TTestMustacheOutput.TestStringOutput; + +Var + SO : TMustacheStringOutput; + +begin + SO:=TMustacheStringOutput.Create; + try + AssertEquals('Empty start','',SO.Data); + SO.Output('abc'); + AssertEquals('Output 1','abc',SO.Data); + SO.Output('def'); + AssertEquals('Output 2','abcdef',SO.Data); + finally + SO.Free; + end; + +end; + +function TTestMustacheParser.CreateParser: TMustacheParser; +begin + Result:=TMustacheParser.Create; +end; + +procedure TTestMustacheParser.SetUp; +begin + inherited SetUp; +end; + +procedure TTestMustacheParser.TearDown; +begin + inherited TearDown; +end; + +procedure TTestMustacheParser.TestEmpty; + +begin + AssertNotNull('Have parser',Parser); + AssertNull('Have no result',ParseResult); + AssertEquals('Have no template','',Template); +end; + + +procedure TTestMustacheParser.TestText; + +begin + Template:='a simple text'; + CallParser; + AssertResultCount(1); + AssertElement(0,metText,'a simple text'); +end; + +procedure TTestMustacheParser.TestVariable; + +Var + el : TMustacheVariableElement; + +begin + Template:='{{a}}'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement; + AssertFalse('unescape',El.NoUnescape); +end; + +procedure TTestMustacheParser.TestVariableErrNonClosed; + +begin + Template:='{{a'; + AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.'); + Template:='{{a}'; + AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.'); +end; + +procedure TTestMustacheParser.TestVariableAlternateStartStop; +Var + el : TMustacheVariableElement; + +begin + Parser.StartTag:='<<'; + Parser.StopTag:='>>'; + Template:='<<a>>'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement; + AssertFalse('unescape',El.NoUnescape); +end; + +procedure TTestMustacheParser.TestDottedVariable; +begin + Template:='{{a.b}}'; + CallParser; + AssertResultCount(1); + AssertElement(0,metVariable,'a.b'); +end; + +procedure TTestMustacheParser.TestVariableNoUnescape; +Var + el : TMustacheVariableElement; + +begin + Template:='{{{a}}}'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement; + AssertTrue('unescape',El.NoUnescape); +end; + +procedure TTestMustacheParser.TestVariableNoUnescapeErrNonClosed; +begin + Template:='{{{a'; + AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.'); + Template:='{{{a}'; + AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.'); + Template:='{{{a}}'; + AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.'); +end; + +procedure TTestMustacheParser.TestVariableNoUnescapeAlternateStartStop; + +Var + el : TMustacheVariableElement; + +begin + Parser.StartTag:='<<'; + Parser.StopTag:='>>'; + Template:='<<{a}>>'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement; + AssertTrue('unescape',El.NoUnescape); +end; + +procedure TTestMustacheParser.TestComment; + +begin + Parser.StartTag:='<<'; + Parser.StopTag:='>>'; + Template:='<<! a comment>>'; + CallParser; + AssertResultCount(1); + AssertElement(0,metComment,' a comment',TMustacheTextElement); +end; + +procedure TTestMustacheParser.TestCommentSurround; +begin + Template:='ab{{! a comment}}cd'; + CallParser; + AssertResultCount(3); + AssertElement(0,metText,'ab',TMustacheTextElement); + AssertElement(1,metComment,' a comment',TMustacheTextElement); + AssertElement(2,metText,'cd',TMustacheTextElement); +end; + +procedure TTestMustacheParser.TestCommentStandalone; +begin + Template:='a'+sLineBreak+'{{! a comment}}'+sLineBreak+'b'; + CallParser; + AssertResultCount(3); + AssertElement(0,metText,'a'+sLineBreak,TMustacheTextElement); + AssertElement(1,metComment,' a comment',TMustacheTextElement); + AssertElement(2,metText,'b',TMustacheTextElement); +end; + +procedure TTestMustacheParser.TestCommentStandaloneSpaced; +begin + Template:='a'+sLineBreak+' {{! a comment}} '+sLineBreak+'b'; + CallParser; + AssertResultCount(3); + AssertElement(0,metText,'a'+sLineBreak,TMustacheTextElement); + AssertElement(1,metComment,' a comment',TMustacheTextElement); + AssertElement(2,metText,'b',TMustacheTextElement); +end; + +procedure TTestMustacheParser.TestSetDelimiter; + +begin + Template:='{{=<< >>=}}<<! a comment>>'; + CallParser; + AssertResultCount(1); + AssertElement(0,metComment,' a comment',TMustacheTextElement); +end; + +procedure TTestMustacheParser.TestSetDelimiterErrInvalid; +begin + Template:='{{=== ===}}'; + AssertException('Have error',EMustache,@CallParser,'Invalid set delimiter Stop value: == in "== =="'); +end; + +procedure TTestMustacheParser.TestSection; + +Var + el : TMustacheSectionElement; + +begin + Template:='{{#a}}{{/a}}'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement; + AssertEquals('No elements in section',0,el.ChildCount); +end; + +procedure TTestMustacheParser.TestSectionNested; + +Var + el : TMustacheSectionElement; + +begin + Template:='{{#a}}{{#b}}{{/b}}{{/a}}'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement; + AssertEquals('elements in section',1,el.ChildCount); + el:=AssertElement(el,0,metSection,'b',TMustacheSectionElement) as TMustacheSectionElement; + AssertEquals('elements in section sub',0,el.ChildCount); +end; + +procedure TTestMustacheParser.TestSectionErrNotClosed; + +begin + Template:='{{#a}}'; + AssertException('Have error',EMustache,@CallParser,'Structural error: Section "a" on position 1 is not closed.'); +end; + +procedure TTestMustacheParser.TestSectionErrWrongClosed; +begin + Template:='{{#a}}{{#b}}{{/a}}{{/b}}'; + AssertException('Have error',EMustache,@CallParser,'Structural error: Section "b" on position 7 is closed by tag "a" on position 13.'); +end; + +procedure TTestMustacheParser.TestSectionErrNotStarted; +begin + Template:='{{/a}}'; + AssertException('Have error',EMustache,@CallParser,'Structural error: Section "a" on position 1 was never opened.'); +end; + +procedure TTestMustacheParser.TestTextSection; + +Var + el : TMustacheSectionElement; + +begin + Template:='{{#a}}bbb{{/a}}'; + CallParser; + AssertResultCount(1); + el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement; + AssertEquals('No elements in section',1,el.ChildCount); + AssertElement(el,0,metText,'bbb'); +end; + +procedure TTestMustacheParser.TestPartial; + +Var + el : TMustachePartialElement; + +begin + AddPartial('part','bcd'); + Template:='a{{>part}}e'; + CallParser; + AssertResultCount(3); + AssertElement(0,metText,'a',TMustacheTextElement); + el:=AssertElement(1,metPartial,'part',TMustachePartialElement) as TMustachePartialElement; + AssertElement(2,metText,'e',TMustacheTextElement); + AssertEquals('Correct partial','part',El.Partial.Data); + AssertEquals('Correct partial',1,El.Partial.ChildCount); + AssertElement(el.Partial,0,metText,'bcd',TMustacheTextElement); +end; + + +initialization + RegisterTests([TTestMustacheParser,TTestMustacheOutput,TTestMustacheElement]); +end. + diff --git a/packages/fcl-mustache/tests/tcspecs.pas b/packages/fcl-mustache/tests/tcspecs.pas new file mode 100644 index 0000000000..5892733e37 --- /dev/null +++ b/packages/fcl-mustache/tests/tcspecs.pas @@ -0,0 +1,188 @@ +{ + This file is part of the Free Pascal Run time library. + Copyright (c) 2021 by Michael Van Canneyt (michael@freepascal.org) + + testcase for official Mustache tests + + See the File COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit tcspecs; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, testregistry, fpmustache, fpjson, jsonparser; + +Type + + { TTestMustacheSpecs } + + TTestMustacheSpecs = class(TTestCase) + private + FTests: TJSONArray; + procedure RunMustacheTest(aIndex: Integer; aTest: TJSONObject); + Public + class var BaseDir : string; + Public + Procedure Setup; override; + Procedure TearDown; override; + Procedure DoTest(aFileName : string); + Property Tests : TJSONArray Read FTests; + Published + Procedure TestComments; + Procedure TestDelimiters; + Procedure TestInterpolation; + Procedure TestInverted; + Procedure TestPartials; + Procedure TestSections; + end; + + +implementation + +{ TTestMustacheSpecs } + +procedure TTestMustacheSpecs.RunMustacheTest(aIndex : Integer; aTest : TJSONObject); + +Var + M : TMustache; + aTempl,aErr,aRes,aName : TMustacheString; + Parts : TJSONObject; + I : Integer; + Ok : Boolean; + + Procedure TreeDump; + + begin + if not OK then + begin + Writeln('Tree dump:'); + Writeln(M.Dump); + end; + end; + + Procedure InputDump; + + begin + Writeln('Test : ',aIndex); + writeln(aTempl); + writeln(StringReplace(StringReplace(aTempl,#10,' ',[rfReplaceAll]),#13,' ',[rfReplaceAll])); + aName:=''; + While Length(aName)<Length(aTempl) do + aName:=AName+'1234567890'; + Writeln(aName); + end; + +begin + OK:=False; + aTempl:=aTest.Get('template',''); + // InputDump; + M:=TMustache.CreateMustache(Nil,aTempl); + try + // Load partials + Parts:=aTest.Get('partials',TJSONObject(Nil)); + if Assigned(Parts) then + for I:=0 to Parts.Count-1 do + M.Partials.Add(Parts.Names[i]+'='+Parts.Items[i].AsString); + // Set test name and run tests + aName:='Test '+IntToStr(aIndex)+': '+aTest.Get('name',''); + Try + aErr:=''; + aRes:=m.Render(aTest.Get('data',TJSONObject(Nil))); + except + on e : exception do + aErr:=E.ClassName+' '+E.message; + end; + if aErr<>'' then + Fail(aName+': Unexpected error: '+aErr); + AssertEquals(aName,aTest.Get('expected',''),aRes); + OK:=true; + finally + // TreeDump; + M.Free; + end; +end; + +procedure TTestMustacheSpecs.Setup; +begin + inherited Setup; +end; + +procedure TTestMustacheSpecs.TearDown; +begin + inherited TearDown; +end; + +procedure TTestMustacheSpecs.DoTest(aFileName: string); + +Var + I : Integer; + F : TFileStream; + D : TJSONData; + FN : String; + +begin + D:=Nil; + FN:=IncludeTrailingPathDelimiter(BaseDir)+aFileName+'.json'; + F:=TFileStream.Create(FN,fmOpenRead or fmShareDenyWrite); + try + D:=GetJSON(F); + if D is TJSONObject then + begin + Ftests:=(D as TJSONObject).Get('tests',TJSONArray(Nil)); + if (FTests=Nil) then + Fail('Invalid mustache tests in '+FN); + end + else + Fail('Invalid JSON object in '+FN); + For I:=0 to Tests.Count-1 do + RunMustacheTest(I,Tests.Items[i] as TJSONObject); + finally + D.Free; + F.Free; + end; +end; + +procedure TTestMustacheSpecs.TestComments; +begin + DoTest('comments'); +end; + +procedure TTestMustacheSpecs.TestDelimiters; +begin + DoTest('delimiters'); +end; + +procedure TTestMustacheSpecs.TestInterpolation; +begin + DoTest('interpolation'); +end; + +procedure TTestMustacheSpecs.TestInverted; +begin + DoTest('inverted'); +end; + +procedure TTestMustacheSpecs.TestPartials; +begin + DoTest('partials'); +end; + +procedure TTestMustacheSpecs.TestSections; +begin + DoTest('sections'); +end; + +begin + TTestMustacheSpecs.BaseDir:='spec/'; + RegisterTest(TTestMustacheSpecs); +end. + diff --git a/packages/fcl-mustache/tests/testmustache.lpi b/packages/fcl-mustache/tests/testmustache.lpi new file mode 100644 index 0000000000..6a8b3c1be6 --- /dev/null +++ b/packages/fcl-mustache/tests/testmustache.lpi @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="12"/> + <General> + <Flags> + <SaveOnlyProjectUnits Value="True"/> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <Title Value="testmustache"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="FCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="testmustache.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="tcmustache.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="tcspecs.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="tcexmustache.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="tcbasemustache.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="tcdbmustache.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="testmustache"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../src"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/packages/fcl-mustache/tests/testmustache.lpr b/packages/fcl-mustache/tests/testmustache.lpr new file mode 100644 index 0000000000..421c0a679c --- /dev/null +++ b/packages/fcl-mustache/tests/testmustache.lpr @@ -0,0 +1,29 @@ +program testmustache; + +{$mode objfpc}{$H+} + +uses + Classes, consoletestrunner, tcmustache, tcspecs, + tcexmustache, tcbasemustache, tcdbmustache; + +type + + { TMyTestRunner } + + TMyTestRunner = class(TTestRunner) + protected + // override the protected methods of TTestRunner to customize its behavior + end; + +var + Application: TMyTestRunner; + +begin + DefaultFormat:=fPlain; + DefaultRunAllTests:=True; + Application := TMyTestRunner.Create(nil); + Application.Initialize; + Application.Title := 'FPCUnit Console test runner'; + Application.Run; + Application.Free; +end. diff --git a/packages/fpmake_add.inc b/packages/fpmake_add.inc index 7cdfb19c13..63d4724bfd 100644 --- a/packages/fpmake_add.inc +++ b/packages/fpmake_add.inc @@ -145,4 +145,5 @@ add_ide(ADirectory+IncludeTrailingPathDelimiter('ide')); add_vclcompat(ADirectory+IncludeTrailingPathDelimiter('vcl-compat')); add_qlunits(ADirectory+IncludeTrailingPathDelimiter('qlunits')); + add_mustache(ADirectory+IncludeTrailingPathDelimiter('fcl-mustache')); diff --git a/packages/fpmake_proc.inc b/packages/fpmake_proc.inc index 169e4ad060..799737deb7 100644 --- a/packages/fpmake_proc.inc +++ b/packages/fpmake_proc.inc @@ -821,4 +821,10 @@ begin {$include qlunits/fpmake.pp} end; +procedure add_mustache(const ADirectory: string); +begin + with Installer do +{$include fcl-mustache/fpmake.pp} +end; + {$include ide/fpmake.pp} -- cgit v1.2.1 From d92dcde98b200093dd9547dc7610210aca94cbd9 Mon Sep 17 00:00:00 2001 From: michael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 20 Apr 2021 12:21:07 +0000 Subject: * Forgot to commit git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49241 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-mustache/Makefile | 3222 ++++++++++++++++++++++++++++++++++++ packages/fcl-mustache/Makefile.fpc | 128 ++ packages/fcl-mustache/fpmake.pp | 49 + 3 files changed, 3399 insertions(+) create mode 100644 packages/fcl-mustache/Makefile create mode 100644 packages/fcl-mustache/Makefile.fpc create mode 100644 packages/fcl-mustache/fpmake.pp diff --git a/packages/fcl-mustache/Makefile b/packages/fcl-mustache/Makefile new file mode 100644 index 0000000000..32529caba3 --- /dev/null +++ b/packages/fcl-mustache/Makefile @@ -0,0 +1,3222 @@ +# +# Don't edit, this file is generated by FPCMake Version 2.0.0 +# +default: all +MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc +BSDs = freebsd netbsd openbsd darwin dragonfly +UNIXs = linux $(BSDs) solaris qnx haiku aix +LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari +OSNeedsComspecToRunBatch = go32v2 watcom +FORCE: +.PHONY: FORCE +override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH))) +ifneq ($(findstring darwin,$(OSTYPE)),) +inUnix=1 #darwin +SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH))) +else +ifeq ($(findstring ;,$(PATH)),) +inUnix=1 +SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH))) +else +SEARCHPATH:=$(subst ;, ,$(PATH)) +endif +endif +SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE)))) +PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH)))) +ifeq ($(PWD),) +PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH)))) +ifeq ($(PWD),) +$(error You need the GNU utils package to use this Makefile) +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT= +endif +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT=.exe +endif +ifndef inUnix +ifeq ($(OS),Windows_NT) +inWinNT=1 +else +ifdef OS2_SHELL +inOS2=1 +endif +endif +else +ifneq ($(findstring cygdrive,$(PATH)),) +inCygWin=1 +endif +endif +ifdef inUnix +SRCBATCHEXT=.sh +else +ifdef inOS2 +SRCBATCHEXT=.cmd +else +SRCBATCHEXT=.bat +endif +endif +ifdef COMSPEC +ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),) +ifndef RUNBATCH +RUNBATCH=$(COMSPEC) /C +endif +endif +endif +ifdef inUnix +PATHSEP=/ +else +PATHSEP:=$(subst /,\,/) +ifdef inCygWin +PATHSEP=/ +endif +endif +ifdef PWD +BASEDIR:=$(subst \,/,$(shell $(PWD))) +ifdef inCygWin +ifneq ($(findstring /cygdrive/,$(BASEDIR)),) +BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR)) +BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR))) +BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR)) +endif +endif +else +BASEDIR=. +endif +ifdef inOS2 +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO=echo +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +endif +override DEFAULT_FPCDIR=../.. +ifndef FPC +ifdef PP +FPC=$(PP) +endif +endif +ifndef FPC +FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(FPCPROG),) +FPCPROG:=$(firstword $(FPCPROG)) +ifneq ($(CPU_TARGET),) +FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB) +else +FPC:=$(shell $(FPCPROG) -PB) +endif +ifneq ($(findstring Error,$(FPC)),) +override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +else +ifeq ($(strip $(wildcard $(FPC))),) +FPC:=$(firstword $(FPCPROG)) +endif +endif +else +override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +endif +endif +override FPC:=$(subst $(SRCEXEEXT),,$(FPC)) +override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT) +FOUNDFPC:=$(strip $(wildcard $(FPC))) +ifeq ($(FOUNDFPC),) +FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH)))) +ifeq ($(FOUNDFPC),) +$(error Compiler $(FPC) not found) +endif +endif +ifndef FPC_COMPILERINFO +FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO) +endif +ifndef FPC_VERSION +FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO)) +endif +export FPC FPC_VERSION FPC_COMPILERINFO +unexport CHECKDEPEND ALLDEPENDENCIES +ifndef CPU_TARGET +ifdef CPU_TARGET_DEFAULT +CPU_TARGET=$(CPU_TARGET_DEFAULT) +endif +endif +ifndef OS_TARGET +ifdef OS_TARGET_DEFAULT +OS_TARGET=$(OS_TARGET_DEFAULT) +endif +endif +ifndef CPU_SOURCE +CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO)) +endif +ifndef CPU_TARGET +CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO)) +endif +ifndef OS_SOURCE +OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO)) +endif +ifndef OS_TARGET +OS_TARGET:=$(word 5,$(FPC_COMPILERINFO)) +endif +FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET) +FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE) +ifeq ($(CPU_TARGET),armeb) +ARCH=arm +override FPCOPT+=-Cb +else +ifeq ($(CPU_TARGET),armel) +ARCH=arm +override FPCOPT+=-CaEABI +else +ARCH=$(CPU_TARGET) +endif +endif +ifeq ($(FULL_TARGET),arm-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for arm-embedded, a sub-architecture (e.g. SUBARCH=armv4t or SUBARCH=armv7m) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),avr-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for avr-embedded, a sub-architecture (e.g. SUBARCH=avr25 or SUBARCH=avr35) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),mipsel-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for mipsel-embedded, a sub-architecture (e.g. SUBARCH=pic32mx) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),xtensa-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for xtensa-embedded, a sub-architecture (e.g. SUBARCH=lx106 or SUBARCH=lx6) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),xtensa-freertos) +ifeq ($(SUBARCH),) +$(error When compiling for xtensa-freertos, a sub-architecture (e.g. SUBARCH=lx106 or SUBARCH=lx6) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),arm-freertos) +ifeq ($(SUBARCH),) +$(error When compiling for arm-freertos, a sub-architecture (e.g. SUBARCH=armv6m or SUBARCH=armv7em) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),) +TARGETSUFFIX=$(OS_TARGET) +SOURCESUFFIX=$(OS_SOURCE) +else +ifneq ($(findstring $(OS_TARGET),$(LIMIT83fs)),) +TARGETSUFFIX=$(OS_TARGET) +else +TARGETSUFFIX=$(FULL_TARGET) +endif +SOURCESUFFIX=$(FULL_SOURCE) +endif +ifneq ($(FULL_TARGET),$(FULL_SOURCE)) +CROSSCOMPILE=1 +endif +ifeq ($(findstring makefile,$(MAKECMDGOALS)),) +ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),) +$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first) +endif +endif +ifneq ($(findstring $(OS_TARGET),$(BSDs)),) +BSDhier=1 +endif +ifeq ($(OS_TARGET),linux) +linuxHier=1 +endif +ifndef CROSSCOMPILE +BUILDFULLNATIVE=1 +export BUILDFULLNATIVE +endif +ifdef BUILDFULLNATIVE +BUILDNATIVE=1 +export BUILDNATIVE +endif +export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE +ifdef FPCDIR +override FPCDIR:=$(subst \,/,$(FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),) +override FPCDIR=wrong +endif +else +override FPCDIR=wrong +endif +ifdef DEFAULT_FPCDIR +ifeq ($(FPCDIR),wrong) +override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),) +override FPCDIR=wrong +endif +endif +endif +ifeq ($(FPCDIR),wrong) +ifdef inUnix +override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION) +ifeq ($(wildcard $(FPCDIR)/units),) +override FPCDIR=/usr/lib/fpc/$(FPC_VERSION) +endif +else +override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH)))))) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),) +override FPCDIR:=$(BASEDIR) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),) +override FPCDIR=c:/pp +endif +endif +endif +endif +endif +ifndef CROSSBINDIR +CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX)) +endif +ifneq ($(findstring $(OS_TARGET),darwin iphonesim ios),) +ifneq ($(findstring $(OS_SOURCE),darwin ios),) +DARWIN2DARWIN=1 +endif +endif +ifndef BINUTILSPREFIX +ifndef CROSSBINDIR +ifdef CROSSCOMPILE +ifneq ($(OS_TARGET),msdos) +ifndef DARWIN2DARWIN +ifneq ($(CPU_TARGET),jvm) +BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)- +ifeq ($(OS_TARGET),android) +ifeq ($(CPU_TARGET),arm) +BINUTILSPREFIX=arm-linux-androideabi- +else +ifeq ($(CPU_TARGET),i386) +BINUTILSPREFIX=i686-linux-android- +else +BINUTILSPREFIX=$(CPU_TARGET)-linux-android- +endif +endif +endif +endif +endif +else +BINUTILSPREFIX=$(OS_TARGET)- +endif +endif +endif +endif +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX)) +ifeq ($(UNITSDIR),) +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET)) +endif +PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages) +ifndef FPCFPMAKE +ifdef CROSSCOMPILE +ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),) +FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(FPCPROG),) +FPCPROG:=$(firstword $(FPCPROG)) +FPCFPMAKE:=$(shell $(FPCPROG) -PB) +ifeq ($(strip $(wildcard $(FPCFPMAKE))),) +FPCFPMAKE:=$(firstword $(FPCPROG)) +endif +else +override FPCFPMAKE=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +endif +else +FPCFPMAKE=$(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))) +FPMAKE_SKIP_CONFIG=-n +export FPCFPMAKE +export FPMAKE_SKIP_CONFIG +endif +else +FPMAKE_SKIP_CONFIG=-n +FPCFPMAKE=$(FPC) +endif +endif +override PACKAGE_NAME=fcl-mustache +override PACKAGE_VERSION=3.3.1 +FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT)) +ifdef OS_TARGET +FPC_TARGETOPT+=--os=$(OS_TARGET) +endif +ifdef CPU_TARGET +FPC_TARGETOPT+=--cpu=$(CPU_TARGET) +endif +LOCALFPMAKE=./fpmake$(SRCEXEEXT) +PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FPMKUNIT),) +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE) +endif +else +PACKAGEDIR_FPMKUNIT= +UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FPMKUNIT),) +UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT)) +else +UNITDIR_FPMKUNIT= +endif +endif +ifdef UNITDIR_FPMAKE_FPMKUNIT +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT) +endif +override INSTALL_FPCPACKAGE=y +ifdef REQUIRE_UNITSDIR +override UNITSDIR+=$(REQUIRE_UNITSDIR) +endif +ifdef REQUIRE_PACKAGESDIR +override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR) +endif +ifdef ZIPINSTALL +ifneq ($(findstring $(OS_TARGET),$(UNIXs)),) +UNIXHier=1 +endif +else +ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),) +UNIXHier=1 +endif +endif +ifndef INSTALL_PREFIX +ifdef PREFIX +INSTALL_PREFIX=$(PREFIX) +endif +endif +ifndef INSTALL_PREFIX +ifdef UNIXHier +INSTALL_PREFIX=/usr/local +else +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=/pp +else +INSTALL_BASEDIR:=/$(PACKAGE_NAME) +endif +endif +endif +export INSTALL_PREFIX +ifdef INSTALL_FPCSUBDIR +export INSTALL_FPCSUBDIR +endif +ifndef DIST_DESTDIR +DIST_DESTDIR:=$(BASEDIR) +endif +export DIST_DESTDIR +ifndef COMPILER_UNITTARGETDIR +ifdef PACKAGEDIR_MAIN +COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX) +else +COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX) +endif +endif +ifndef COMPILER_TARGETDIR +COMPILER_TARGETDIR=. +endif +ifndef INSTALL_BASEDIR +ifdef UNIXHier +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION) +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME) +endif +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX) +endif +endif +ifndef INSTALL_BINDIR +ifdef UNIXHier +INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin +else +INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin +ifdef INSTALL_FPCPACKAGE +ifdef CROSSCOMPILE +ifdef CROSSINSTALL +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX) +else +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX) +endif +else +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX) +endif +endif +endif +endif +ifndef INSTALL_UNITDIR +INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX) +ifdef INSTALL_FPCPACKAGE +ifdef PACKAGE_NAME +INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME) +endif +endif +endif +ifndef INSTALL_LIBDIR +ifdef UNIXHier +INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib +else +INSTALL_LIBDIR:=$(INSTALL_UNITDIR) +endif +endif +ifndef INSTALL_SOURCEDIR +ifdef UNIXHier +ifdef BSDhier +SRCPREFIXDIR=share/src +else +ifdef linuxHier +SRCPREFIXDIR=share/src +else +SRCPREFIXDIR=src +endif +endif +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source +endif +endif +endif +ifndef INSTALL_DOCDIR +ifdef UNIXHier +ifdef BSDhier +DOCPREFIXDIR=share/doc +else +ifdef linuxHier +DOCPREFIXDIR=share/doc +else +DOCPREFIXDIR=doc +endif +endif +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc +endif +endif +endif +ifndef INSTALL_EXAMPLEDIR +ifdef UNIXHier +ifdef INSTALL_FPCPACKAGE +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +ifdef linuxHier +INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME) +endif +endif +else +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +else +ifdef linuxHier +INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +endif +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples +endif +endif +endif +ifndef INSTALL_DATADIR +INSTALL_DATADIR=$(INSTALL_BASEDIR) +endif +ifndef INSTALL_SHAREDDIR +INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib +endif +ifdef CROSSCOMPILE +ifndef CROSSBINDIR +CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX)) +ifeq ($(CROSSBINDIR),) +CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE)) +endif +endif +else +CROSSBINDIR= +endif +ifeq ($(OS_SOURCE),linux) +ifndef GCCLIBDIR +ifeq ($(CPU_TARGET),i386) +ifneq ($(findstring x86_64,$(shell uname -a)),) +ifeq ($(BINUTILSPREFIX),) +GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`) +else +CROSSGCCOPT=-m32 +endif +endif +endif +ifeq ($(CPU_TARGET),powerpc) +ifeq ($(BINUTILSPREFIX),) +GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`) +else +CROSSGCCOPT=-m32 +endif +endif +ifeq ($(CPU_TARGET),powerpc64) +ifeq ($(BINUTILSPREFIX),) +GCCLIBDIR:=$(shell dirname `gcc -m64 -print-libgcc-file-name`) +else +CROSSGCCOPT=-m64 +endif +endif +ifeq ($(CPU_TARGET),sparc) +ifneq ($(findstring sparc64,$(shell uname -a)),) +ifeq ($(BINUTILSPREFIX),) +GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`) +else +ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),) +CROSSGCCOPT=-mabi=32 +else +CROSSGCCOPT=-m32 +endif +endif +endif +endif +endif +ifdef FPCFPMAKE +FPCFPMAKE_CPU_TARGET=$(shell $(FPCFPMAKE) -iTP) +ifeq ($(CPU_TARGET),$(FPCFPMAKE_CPU_TARGET)) +FPCMAKEGCCLIBDIR:=$(GCCLIBDIR) +else +ifneq ($(findstring $(FPCFPMAKE_CPU_TARGET),aarch64 powerpc64 riscv64 sparc64 x86_64),) +FPCMAKE_CROSSGCCOPT=-m64 +else +ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips64 mips64el),) +FPCMAKE_CROSSGCCOPT=-mabi=64 +else +ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),) +FPCMAKE_CROSSGCCOPT=-mabi=32 +else +FPCMAKE_CROSSGCCOPT=-m32 +endif +endif +endif +FPCMAKEGCCLIBDIR:=$(shell dirname `gcc $(FPCMAKE_CROSSGCCOPT) -print-libgcc-file-name`) +endif +endif +ifndef FPCMAKEGCCLIBDIR +FPCMAKEGCCLIBDIR:=$(shell dirname `gcc -print-libgcc-file-name`) +endif +ifndef GCCLIBDIR +CROSSGCC=$(strip $(wildcard $(addsuffix /$(BINUTILSPREFIX)gcc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(CROSSGCC),) +GCCLIBDIR:=$(shell dirname `$(CROSSGCC) $(CROSSGCCOPT) -print-libgcc-file-name`) +endif +endif +endif +ifdef inUnix +ifeq ($(OS_SOURCE),netbsd) +OTHERLIBDIR:=/usr/pkg/lib +endif +export GCCLIBDIR FPCMAKEGCCLIBDIR OTHERLIBDIR +endif +BATCHEXT=.bat +LOADEREXT=.as +EXEEXT=.exe +PPLEXT=.ppl +PPUEXT=.ppu +OEXT=.o +LTOEXT=.bc +ASMEXT=.s +SMARTEXT=.sl +STATICLIBEXT=.a +SHAREDLIBEXT=.so +SHAREDLIBPREFIX=libfp +STATICLIBPREFIX=libp +IMPORTLIBPREFIX=libimp +RSTEXT=.rst +EXEDBGEXT=.dbg +ifeq ($(OS_TARGET),go32v1) +STATICLIBPREFIX= +SHORTSUFFIX=v1 +endif +ifeq ($(OS_TARGET),go32v2) +STATICLIBPREFIX= +SHORTSUFFIX=dos +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),watcom) +STATICLIBPREFIX= +OEXT=.obj +ASMEXT=.asm +SHAREDLIBEXT=.dll +SHORTSUFFIX=wat +IMPORTLIBPREFIX= +endif +ifneq ($(CPU_TARGET),jvm) +ifeq ($(OS_TARGET),android) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=lnx +endif +endif +ifeq ($(OS_TARGET),linux) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=lnx +endif +ifeq ($(OS_TARGET),dragonfly) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=df +endif +ifeq ($(OS_TARGET),freebsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=fbs +endif +ifeq ($(OS_TARGET),netbsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=nbs +endif +ifeq ($(OS_TARGET),openbsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=obs +endif +ifeq ($(OS_TARGET),win32) +SHAREDLIBEXT=.dll +SHORTSUFFIX=w32 +endif +ifeq ($(OS_TARGET),os2) +BATCHEXT=.cmd +AOUTEXT=.out +STATICLIBPREFIX= +SHAREDLIBEXT=.dll +SHORTSUFFIX=os2 +ECHO=echo +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),emx) +BATCHEXT=.cmd +AOUTEXT=.out +STATICLIBPREFIX= +SHAREDLIBEXT=.dll +SHORTSUFFIX=emx +ECHO=echo +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),amiga) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=amg +endif +ifeq ($(OS_TARGET),aros) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=aros +endif +ifeq ($(OS_TARGET),morphos) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=mos +endif +ifeq ($(OS_TARGET),atari) +EXEEXT=.ttp +SHORTSUFFIX=ata +endif +ifeq ($(OS_TARGET),beos) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=be +endif +ifeq ($(OS_TARGET),haiku) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=hai +endif +ifeq ($(OS_TARGET),solaris) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=sun +endif +ifeq ($(OS_TARGET),qnx) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=qnx +endif +ifeq ($(OS_TARGET),netware) +EXEEXT=.nlm +STATICLIBPREFIX= +SHORTSUFFIX=nw +IMPORTLIBPREFIX=imp +endif +ifeq ($(OS_TARGET),netwlibc) +EXEEXT=.nlm +STATICLIBPREFIX= +SHORTSUFFIX=nwl +IMPORTLIBPREFIX=imp +endif +ifeq ($(OS_TARGET),macosclassic) +BATCHEXT= +EXEEXT= +DEBUGSYMEXT=.xcoff +SHORTSUFFIX=mac +IMPORTLIBPREFIX=imp +endif +ifneq ($(findstring $(OS_TARGET),darwin iphonesim ios),) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=dwn +EXEDBGEXT=.dSYM +endif +ifeq ($(OS_TARGET),gba) +EXEEXT=.gba +SHAREDLIBEXT=.so +SHORTSUFFIX=gba +endif +ifeq ($(OS_TARGET),symbian) +SHAREDLIBEXT=.dll +SHORTSUFFIX=symbian +endif +ifeq ($(OS_TARGET),NativeNT) +SHAREDLIBEXT=.dll +SHORTSUFFIX=nativent +endif +ifeq ($(OS_TARGET),wii) +EXEEXT=.dol +SHAREDLIBEXT=.so +SHORTSUFFIX=wii +endif +ifeq ($(OS_TARGET),aix) +BATCHEXT=.sh +EXEEXT= +SHAREDLIBEXT=.a +SHORTSUFFIX=aix +endif +ifeq ($(OS_TARGET),java) +OEXT=.class +ASMEXT=.j +SHAREDLIBEXT=.jar +SHORTSUFFIX=java +endif +ifeq ($(CPU_TARGET),jvm) +ifeq ($(OS_TARGET),android) +OEXT=.class +ASMEXT=.j +SHAREDLIBEXT=.jar +SHORTSUFFIX=android +endif +endif +ifeq ($(OS_TARGET),msdos) +STATICLIBPREFIX= +STATICLIBEXT=.a +SHORTSUFFIX=d16 +endif +ifeq ($(OS_TARGET),msxdos) +STATICLIBPREFIX= +STATICLIBEXT=.a +SHORTSUFFIX=msd +endif +ifeq ($(OS_TARGET),embedded) +ifeq ($(CPU_TARGET),i8086) +STATICLIBPREFIX= +STATICLIBEXT=.a +else +EXEEXT=.bin +endif +ifeq ($(CPU_TARGET),z80) +OEXT=.rel +endif +SHORTSUFFIX=emb +endif +ifeq ($(OS_TARGET),win16) +STATICLIBPREFIX= +STATICLIBEXT=.a +SHAREDLIBEXT=.dll +SHORTSUFFIX=w16 +endif +ifeq ($(OS_TARGET),zxspectrum) +OEXT=.rel +endif +ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),) +FPCMADE=fpcmade.$(SHORTSUFFIX) +ZIPSUFFIX=$(SHORTSUFFIX) +ZIPCROSSPREFIX= +ZIPSOURCESUFFIX=src +ZIPEXAMPLESUFFIX=exm +else +FPCMADE=fpcmade.$(TARGETSUFFIX) +ZIPSOURCESUFFIX=.source +ZIPEXAMPLESUFFIX=.examples +ifdef CROSSCOMPILE +ZIPSUFFIX=.$(SOURCESUFFIX) +ZIPCROSSPREFIX=$(TARGETSUFFIX)- +else +ZIPSUFFIX=.$(TARGETSUFFIX) +ZIPCROSSPREFIX= +endif +endif +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO= __missing_command_ECHO +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +ifndef DATE +DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE= __missing_command_DATE +else +DATE:=$(firstword $(DATE)) +endif +else +DATE:=$(firstword $(DATE)) +endif +endif +export DATE +ifndef GINSTALL +GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL= __missing_command_GINSTALL +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +endif +export GINSTALL +ifndef CPPROG +CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(CPPROG),) +CPPROG= __missing_command_CPPROG +else +CPPROG:=$(firstword $(CPPROG)) +endif +endif +export CPPROG +ifndef RMPROG +RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(RMPROG),) +RMPROG= __missing_command_RMPROG +else +RMPROG:=$(firstword $(RMPROG)) +endif +endif +export RMPROG +ifndef MVPROG +MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MVPROG),) +MVPROG= __missing_command_MVPROG +else +MVPROG:=$(firstword $(MVPROG)) +endif +endif +export MVPROG +ifndef MKDIRPROG +MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MKDIRPROG),) +MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MKDIRPROG),) +MKDIRPROG= __missing_command_MKDIRPROG +else +MKDIRPROG:=$(firstword $(MKDIRPROG)) +endif +else +MKDIRPROG:=$(firstword $(MKDIRPROG)) +endif +endif +export MKDIRPROG +ifndef ECHOREDIR +ifndef inUnix +ECHOREDIR=echo +else +ECHOREDIR=$(ECHO) +endif +endif +ifndef COPY +COPY:=$(CPPROG) -fp +endif +ifndef COPYTREE +COPYTREE:=$(CPPROG) -Rfp +endif +ifndef MKDIRTREE +MKDIRTREE:=$(MKDIRPROG) -p +endif +ifndef MOVE +MOVE:=$(MVPROG) -f +endif +ifndef DEL +DEL:=$(RMPROG) -f +endif +ifndef DELTREE +DELTREE:=$(RMPROG) -rf +endif +ifndef INSTALL +ifdef inUnix +INSTALL:=$(GINSTALL) -c -m 644 +else +INSTALL:=$(COPY) +endif +endif +ifndef INSTALLEXE +ifdef inUnix +INSTALLEXE:=$(GINSTALL) -c -m 755 +else +INSTALLEXE:=$(COPY) +endif +endif +ifndef MKDIR +MKDIR:=$(GINSTALL) -m 755 -d +endif +export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR +ifndef PPUMOVE +PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(PPUMOVE),) +PPUMOVE= __missing_command_PPUMOVE +else +PPUMOVE:=$(firstword $(PPUMOVE)) +endif +endif +export PPUMOVE +ifndef FPCMAKE +FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(FPCMAKE),) +FPCMAKE= __missing_command_FPCMAKE +else +FPCMAKE:=$(firstword $(FPCMAKE)) +endif +endif +export FPCMAKE +ifndef ZIPPROG +ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ZIPPROG),) +ZIPPROG= __missing_command_ZIPPROG +else +ZIPPROG:=$(firstword $(ZIPPROG)) +endif +endif +export ZIPPROG +ifndef TARPROG +TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(TARPROG),) +TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(TARPROG),) +TARPROG= __missing_command_TARPROG +else +TARPROG:=$(firstword $(TARPROG)) +endif +else +TARPROG:=$(firstword $(TARPROG)) +endif +endif +export TARPROG +ASNAME=$(BINUTILSPREFIX)as +LDNAME=$(BINUTILSPREFIX)ld +ARNAME=$(BINUTILSPREFIX)ar +RCNAME=$(BINUTILSPREFIX)rc +NASMNAME=$(BINUTILSPREFIX)nasm +ifndef ASPROG +ifdef CROSSBINDIR +ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT) +else +ASPROG=$(ASNAME) +endif +endif +ifndef LDPROG +ifdef CROSSBINDIR +LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT) +else +LDPROG=$(LDNAME) +endif +endif +ifndef RCPROG +ifdef CROSSBINDIR +RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT) +else +RCPROG=$(RCNAME) +endif +endif +ifndef ARPROG +ifdef CROSSBINDIR +ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT) +else +ARPROG=$(ARNAME) +endif +endif +ifndef NASMPROG +ifdef CROSSBINDIR +NASMPROG=$(CROSSBINDIR)/$(NASMNAME)$(SRCEXEEXT) +else +NASMPROG=$(NASMNAME) +endif +endif +AS=$(ASPROG) +LD=$(LDPROG) +RC=$(RCPROG) +AR=$(ARPROG) +NASM=$(NASMPROG) +ifdef inUnix +PPAS=./ppas$(SRCBATCHEXT) +else +PPAS=ppas$(SRCBATCHEXT) +endif +ifdef inUnix +LDCONFIG=ldconfig +else +LDCONFIG= +endif +ifdef DATE +DATESTR:=$(shell $(DATE) +%Y%m%d) +else +DATESTR= +endif +ZIPOPT=-9 +ZIPEXT=.zip +ifeq ($(USETAR),bz2) +TAROPT=vj +TAREXT=.tar.bz2 +else +TAROPT=vz +TAREXT=.tar.gz +endif +override REQUIRE_PACKAGES=rtl fcl-base fcl-db fcl-json +ifeq ($(FULL_TARGET),i386-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-go32v2) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-win32) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-os2) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-beos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-haiku) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-netware) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-openbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-wdosx) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-emx) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-watcom) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-netwlibc) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-wince) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-symbian) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-nativent) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-iphonesim) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i386-aros) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-amiga) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-atari) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-palmos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-macosclassic) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),m68k-sinclairql) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-amiga) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-macosclassic) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-morphos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-wii) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc-aix) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),sparc-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),sparc-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),sparc-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),sparc-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-haiku) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-openbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-win64) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-iphonesim) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-aros) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),x86_64-dragonfly) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-palmos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-wince) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-gba) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-nds) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-symbian) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-aros) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-freertos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),arm-ios) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc64-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),powerpc64-aix) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),avr-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),armeb-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),armeb-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),mips-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),mipsel-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),mipsel-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),mipsel-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),mips64el-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),jvm-java) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),jvm-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i8086-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i8086-msdos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),i8086-win16) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),aarch64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),aarch64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),aarch64-win64) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),aarch64-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),aarch64-ios) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),wasm-wasm) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),sparc64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),riscv32-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),riscv32-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),riscv64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),riscv64-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),xtensa-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),xtensa-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),xtensa-freertos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),z80-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),z80-zxspectrum) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),z80-msxdos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),z80-amstradcpc) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifdef REQUIRE_PACKAGES_RTL +PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_RTL),) +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),) +UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX) +else +UNITDIR_RTL=$(PACKAGEDIR_RTL) +endif +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_RTL)/$(OS_TARGET) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE) +endif +else +PACKAGEDIR_RTL= +UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_RTL),) +UNITDIR_RTL:=$(firstword $(UNITDIR_RTL)) +else +UNITDIR_RTL= +endif +endif +ifdef UNITDIR_RTL +override COMPILER_UNITDIR+=$(UNITDIR_RTL) +endif +ifdef UNITDIR_FPMAKE_RTL +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_RTL) +endif +endif +ifdef REQUIRE_PACKAGES_PASZLIB +PACKAGEDIR_PASZLIB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_PASZLIB),) +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)),) +UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX) +else +UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB) +endif +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_PASZLIB)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_PASZLIB) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_PASZLIB)/$(FPCMADE) +endif +else +PACKAGEDIR_PASZLIB= +UNITDIR_PASZLIB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_PASZLIB),) +UNITDIR_PASZLIB:=$(firstword $(UNITDIR_PASZLIB)) +else +UNITDIR_PASZLIB= +endif +endif +ifdef UNITDIR_PASZLIB +override COMPILER_UNITDIR+=$(UNITDIR_PASZLIB) +endif +ifdef UNITDIR_FPMAKE_PASZLIB +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_PASZLIB) +endif +endif +ifdef REQUIRE_PACKAGES_FCL-PROCESS +PACKAGEDIR_FCL-PROCESS:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FCL-PROCESS),) +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)),) +UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX) +else +UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS) +endif +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FCL-PROCESS) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE) +endif +else +PACKAGEDIR_FCL-PROCESS= +UNITDIR_FCL-PROCESS:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FCL-PROCESS),) +UNITDIR_FCL-PROCESS:=$(firstword $(UNITDIR_FCL-PROCESS)) +else +UNITDIR_FCL-PROCESS= +endif +endif +ifdef UNITDIR_FCL-PROCESS +override COMPILER_UNITDIR+=$(UNITDIR_FCL-PROCESS) +endif +ifdef UNITDIR_FPMAKE_FCL-PROCESS +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-PROCESS) +endif +endif +ifdef REQUIRE_PACKAGES_HASH +PACKAGEDIR_HASH:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /hash/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_HASH),) +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)),) +UNITDIR_HASH=$(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX) +else +UNITDIR_HASH=$(PACKAGEDIR_HASH) +endif +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_HASH)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_HASH) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_HASH)/$(FPCMADE) +endif +else +PACKAGEDIR_HASH= +UNITDIR_HASH:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /hash/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_HASH),) +UNITDIR_HASH:=$(firstword $(UNITDIR_HASH)) +else +UNITDIR_HASH= +endif +endif +ifdef UNITDIR_HASH +override COMPILER_UNITDIR+=$(UNITDIR_HASH) +endif +ifdef UNITDIR_FPMAKE_HASH +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_HASH) +endif +endif +ifdef REQUIRE_PACKAGES_LIBTAR +PACKAGEDIR_LIBTAR:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /libtar/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_LIBTAR),) +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)),) +UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX) +else +UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR) +endif +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_LIBTAR)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_LIBTAR) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_LIBTAR)/$(FPCMADE) +endif +else +PACKAGEDIR_LIBTAR= +UNITDIR_LIBTAR:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /libtar/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_LIBTAR),) +UNITDIR_LIBTAR:=$(firstword $(UNITDIR_LIBTAR)) +else +UNITDIR_LIBTAR= +endif +endif +ifdef UNITDIR_LIBTAR +override COMPILER_UNITDIR+=$(UNITDIR_LIBTAR) +endif +ifdef UNITDIR_FPMAKE_LIBTAR +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_LIBTAR) +endif +endif +ifdef REQUIRE_PACKAGES_FPMKUNIT +PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FPMKUNIT),) +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)),) +UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX) +else +UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE) +endif +else +PACKAGEDIR_FPMKUNIT= +UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FPMKUNIT),) +UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT)) +else +UNITDIR_FPMKUNIT= +endif +endif +ifdef UNITDIR_FPMKUNIT +override COMPILER_UNITDIR+=$(UNITDIR_FPMKUNIT) +endif +ifdef UNITDIR_FPMAKE_FPMKUNIT +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT) +endif +endif +ifdef REQUIRE_PACKAGES_FCL-BASE +PACKAGEDIR_FCL-BASE:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FCL-BASE),) +ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX)),) +UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX) +else +UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE) +endif +ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FCL-BASE)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FCL-BASE) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-BASE)/$(FPCMADE) +endif +else +PACKAGEDIR_FCL-BASE= +UNITDIR_FCL-BASE:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FCL-BASE),) +UNITDIR_FCL-BASE:=$(firstword $(UNITDIR_FCL-BASE)) +else +UNITDIR_FCL-BASE= +endif +endif +ifdef UNITDIR_FCL-BASE +override COMPILER_UNITDIR+=$(UNITDIR_FCL-BASE) +endif +ifdef UNITDIR_FPMAKE_FCL-BASE +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-BASE) +endif +endif +ifdef REQUIRE_PACKAGES_FCL-DB +PACKAGEDIR_FCL-DB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-db/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FCL-DB),) +ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units/$(TARGETSUFFIX)),) +UNITDIR_FCL-DB=$(PACKAGEDIR_FCL-DB)/units/$(TARGETSUFFIX) +else +UNITDIR_FCL-DB=$(PACKAGEDIR_FCL-DB) +endif +ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FCL-DB)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FCL-DB) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-DB)/$(FPCMADE) +endif +else +PACKAGEDIR_FCL-DB= +UNITDIR_FCL-DB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-db/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FCL-DB),) +UNITDIR_FCL-DB:=$(firstword $(UNITDIR_FCL-DB)) +else +UNITDIR_FCL-DB= +endif +endif +ifdef UNITDIR_FCL-DB +override COMPILER_UNITDIR+=$(UNITDIR_FCL-DB) +endif +ifdef UNITDIR_FPMAKE_FCL-DB +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-DB) +endif +endif +ifdef REQUIRE_PACKAGES_FCL-JSON +PACKAGEDIR_FCL-JSON:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FCL-JSON),) +ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX)),) +UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX) +else +UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON) +endif +ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FCL-JSON)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FCL-JSON) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-JSON)/$(FPCMADE) +endif +else +PACKAGEDIR_FCL-JSON= +UNITDIR_FCL-JSON:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FCL-JSON),) +UNITDIR_FCL-JSON:=$(firstword $(UNITDIR_FCL-JSON)) +else +UNITDIR_FCL-JSON= +endif +endif +ifdef UNITDIR_FCL-JSON +override COMPILER_UNITDIR+=$(UNITDIR_FCL-JSON) +endif +ifdef UNITDIR_FPMAKE_FCL-JSON +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-JSON) +endif +endif +ifndef NOCPUDEF +override FPCOPTDEF=$(ARCH) +endif +ifneq ($(OS_TARGET),$(OS_SOURCE)) +override FPCOPT+=-T$(OS_TARGET) +endif +ifneq ($(CPU_TARGET),$(CPU_SOURCE)) +override FPCOPT+=-P$(ARCH) +endif +ifeq ($(OS_SOURCE),openbsd) +override FPCOPT+=-FD$(NEW_BINUTILS_PATH) +override FPCMAKEOPT+=-FD$(NEW_BINUTILS_PATH) +override FPMAKE_BUILD_OPT+=-FD$(NEW_BINUTILS_PATH) +endif +ifndef CROSSBOOTSTRAP +ifneq ($(BINUTILSPREFIX),) +override FPCOPT+=-XP$(BINUTILSPREFIX) +ifneq ($(RLINKPATH),) +override FPCOPT+=-Xr$(RLINKPATH) +endif +endif +endif +ifndef CROSSCOMPILE +ifneq ($(BINUTILSPREFIX),) +override FPCMAKEOPT+=-XP$(BINUTILSPREFIX) +override FPMAKE_BUILD_OPT+=-XP$(BINUTILSPREFIX) +endif +endif +ifdef UNITDIR +override FPCOPT+=$(addprefix -Fu,$(UNITDIR)) +endif +ifdef LIBDIR +override FPCOPT+=$(addprefix -Fl,$(LIBDIR)) +endif +ifdef OBJDIR +override FPCOPT+=$(addprefix -Fo,$(OBJDIR)) +endif +ifdef INCDIR +override FPCOPT+=$(addprefix -Fi,$(INCDIR)) +endif +ifdef LINKSMART +override FPCOPT+=-XX +endif +ifdef CREATESMART +override FPCOPT+=-CX +endif +ifdef DEBUG +override FPCOPT+=-gl +override FPCOPTDEF+=DEBUG +endif +ifdef RELEASE +FPCCPUOPT:=-O2 +override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n +override FPCOPTDEF+=RELEASE +endif +ifdef STRIP +override FPCOPT+=-Xs +endif +ifdef OPTIMIZE +override FPCOPT+=-O2 +endif +ifdef VERBOSE +override FPCOPT+=-vwni +endif +ifdef COMPILER_OPTIONS +override FPCOPT+=$(COMPILER_OPTIONS) +endif +ifdef COMPILER_UNITDIR +override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR)) +endif +ifdef COMPILER_LIBRARYDIR +override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR)) +endif +ifdef COMPILER_OBJECTDIR +override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR)) +endif +ifdef COMPILER_INCLUDEDIR +override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR)) +endif +ifdef CROSSBINDIR +override FPCOPT+=-FD$(CROSSBINDIR) +endif +ifdef COMPILER_TARGETDIR +override FPCOPT+=-FE$(COMPILER_TARGETDIR) +ifeq ($(COMPILER_TARGETDIR),.) +override TARGETDIRPREFIX= +else +override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/ +endif +endif +ifdef COMPILER_UNITTARGETDIR +override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR) +ifeq ($(COMPILER_UNITTARGETDIR),.) +override UNITTARGETDIRPREFIX= +else +override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/ +endif +else +ifdef COMPILER_TARGETDIR +override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR) +override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX) +endif +endif +ifdef CREATESHARED +override FPCOPT+=-Cg +endif +ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),) +ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),) +override FPCOPT+=-Cg +endif +endif +ifdef LINKSHARED +endif +ifdef GCCLIBDIR +override FPCOPT+=-Fl$(GCCLIBDIR) +ifdef FPCMAKEGCCLIBDIR +override FPCMAKEOPT+=-Fl$(FPCMAKEGCCLIBDIR) +else +override FPCMAKEOPT+=-Fl$(GCCLIBDIR) +endif +endif +ifdef OTHERLIBDIR +override FPCOPT+=$(addprefix -Fl,$(OTHERLIBDIR)) +endif +ifdef OPT +override FPCOPT+=$(OPT) +endif +ifdef FPMAKEBUILDOPT +override FPMAKE_BUILD_OPT+=$(FPMAKEBUILDOPT) +endif +ifdef FPCOPTDEF +override FPCOPT+=$(addprefix -d,$(FPCOPTDEF)) +endif +ifdef CFGFILE +override FPCOPT+=@$(CFGFILE) +endif +ifdef USEENV +override FPCEXTCMD:=$(FPCOPT) +override FPCOPT:=!FPCEXTCMD +export FPCEXTCMD +endif +override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET) +override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE) +ifneq ($(AFULL_TARGET),$(AFULL_SOURCE)) +override ACROSSCOMPILE=1 +endif +ifdef ACROSSCOMPILE +override FPCOPT+=$(CROSSOPT) +endif +override COMPILER:=$(strip $(FPC) $(FPCOPT)) +ifneq (,$(findstring -sh ,$(COMPILER))) +UseEXECPPAS=1 +endif +ifneq (,$(findstring -s ,$(COMPILER))) +ifeq ($(FULL_SOURCE),$(FULL_TARGET)) +UseEXECPPAS=1 +endif +endif +ifneq ($(UseEXECPPAS),1) +EXECPPAS= +else +ifdef RUNBATCH +EXECPPAS:=@$(RUNBATCH) $(PPAS) +else +EXECPPAS:=@$(PPAS) +endif +endif +ifdef TARGET_RSTS +override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS)) +override CLEANRSTFILES+=$(RSTFILES) +endif +.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall +ifdef INSTALL_UNITS +override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS)) +endif +ifdef INSTALL_BUILDUNIT +override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES)) +endif +ifdef INSTALLPPUFILES +ifneq ($(IMPORTLIBPREFIX)-$(STATICLIBEXT),$(STATICLIBPREFIX)-$(STATICLIBEXT)) +override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) +else +override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) +endif +ifneq ($(UNITTARGETDIRPREFIX),) +override INSTALLPPUFILENAMES:=$(notdir $(INSTALLPPUFILES)) +override INSTALLPPULINKFILENAMES:=$(notdir $(INSTALLPPULINKFILES)) +override INSTALLPPUFILES=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPUFILENAMES)) +override INSTALLPPULINKFILES=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPULINKFILENAMES))) +endif +override INSTALL_CREATEPACKAGEFPC=1 +endif +ifdef INSTALLEXEFILES +ifneq ($(TARGETDIRPREFIX),) +override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES))) +endif +endif +fpc_install: all $(INSTALLTARGET) +ifdef INSTALLEXEFILES + $(MKDIR) $(INSTALL_BINDIR) + $(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR) +endif +ifdef INSTALL_CREATEPACKAGEFPC +ifdef FPCMAKE +ifdef PACKAGE_VERSION +ifneq ($(wildcard Makefile.fpc),) + $(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) Package.fpc $(INSTALL_UNITDIR) +endif +endif +endif +endif +ifdef INSTALLPPUFILES + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR) +ifneq ($(INSTALLPPULINKFILES),) + $(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR) +endif +ifneq ($(wildcard $(LIB_FULLNAME)),) + $(MKDIR) $(INSTALL_LIBDIR) + $(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR) +ifdef inUnix + ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME) +endif +endif +endif +ifdef INSTALL_FILES + $(MKDIR) $(INSTALL_DATADIR) + $(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR) +endif +fpc_sourceinstall: distclean + $(MKDIR) $(INSTALL_SOURCEDIR) + $(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR) +fpc_exampleinstall: $(EXAMPLEINSTALLTARGET) $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS)) +ifdef HASEXAMPLES + $(MKDIR) $(INSTALL_EXAMPLEDIR) +endif +ifdef EXAMPLESOURCEFILES + $(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR) +endif +ifdef TARGET_EXAMPLEDIRS + $(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR) +endif +.PHONY: fpc_distinstall +fpc_distinstall: install exampleinstall +.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall +ifndef PACKDIR +ifndef inUnix +PACKDIR=$(BASEDIR)/../fpc-pack +else +PACKDIR=/tmp/fpc-pack +endif +endif +ifndef ZIPNAME +ifdef DIST_ZIPNAME +ZIPNAME=$(DIST_ZIPNAME) +else +ZIPNAME=$(PACKAGE_NAME) +endif +endif +ifndef FULLZIPNAME +FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX) +endif +ifndef ZIPTARGET +ifdef DIST_ZIPTARGET +ZIPTARGET=DIST_ZIPTARGET +else +ZIPTARGET=install +endif +endif +ifndef USEZIP +ifdef inUnix +USETAR=1 +endif +endif +ifndef inUnix +USEZIPWRAPPER=1 +endif +ifdef USEZIPWRAPPER +ZIPPATHSEP=$(PATHSEP) +ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT)) +else +ZIPPATHSEP=/ +endif +ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR)) +ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR)) +ifdef USETAR +ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT) +ZIPCMD_ZIP:=$(TARPROG) c$(TAROPT)f $(ZIPDESTFILE) * +else +ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT) +ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) * +endif +fpc_zipinstall: + $(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1 + $(MKDIR) $(DIST_DESTDIR) + $(DEL) $(ZIPDESTFILE) +ifdef USEZIPWRAPPER +ifneq ($(ECHOREDIR),echo) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER) +else + echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER) + echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER) + echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER) +endif +ifdef inUnix + /bin/sh $(ZIPWRAPPER) +else +ifdef RUNBATCH + $(RUNBATCH) $(ZIPWRAPPER) +else + $(ZIPWRAPPER) +endif +endif + $(DEL) $(ZIPWRAPPER) +else + $(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE) +endif + $(DELTREE) $(PACKDIR) +fpc_zipsourceinstall: + $(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX) +fpc_zipexampleinstall: +ifdef HASEXAMPLES + $(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX) +endif +fpc_zipdistinstall: + $(MAKE) fpc_zipinstall ZIPTARGET=distinstall +.PHONY: fpc_clean fpc_cleanall fpc_distclean +ifdef EXEFILES +override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES)) +override CLEANEXEDBGFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEDBGFILES)) +endif +ifdef CLEAN_PROGRAMS +override CLEANEXEFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEEXT), $(CLEAN_PROGRAMS))) +override CLEANEXEDBGFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEDBGEXT), $(CLEAN_PROGRAMS))) +endif +ifdef CLEAN_UNITS +override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS)) +endif +ifdef CLEANPPUFILES +override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) +ifdef DEBUGSYMEXT +override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES)) +endif +override CLEANPPUFILENAMES:=$(CLEANPPUFILES) +override CLEANPPUFILES=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILENAMES)) +override CLEANPPULINKFILENAMES:=$(CLEANPPULINKFILES) +override CLEANPPULINKFILES=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILENAMES))) +endif +fpc_clean: $(CLEANTARGET) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif +ifdef CLEANEXEDBGFILES + -$(DELTREE) $(CLEANEXEDBGFILES) +endif +ifdef CLEANPPUFILES + -$(DEL) $(CLEANPPUFILES) +endif +ifneq ($(CLEANPPULINKFILES),) + -$(DEL) $(CLEANPPULINKFILES) +endif +ifdef CLEANRSTFILES + -$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES)) +endif +ifdef CLEAN_FILES + -$(DEL) $(CLEAN_FILES) +endif +ifdef LIB_NAME + -$(DEL) $(LIB_NAME) $(LIB_FULLNAME) +endif + -$(DEL) $(FPCMADE) *$(FULL_TARGET).fpm Package.fpc *$(ASMEXT) + -$(DEL) $(FPCEXTFILE) $(REDIRFILE) script*.res link*.res *_script.res *_link.res + -$(DEL) $(PPAS) *_ppas$(BATCHEXT) ppas$(BATCHEXT) ppaslink$(BATCHEXT) +fpc_cleanall: $(CLEANTARGET) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif +ifdef COMPILER_UNITTARGETDIR +ifdef CLEANPPUFILES + -$(DEL) $(CLEANPPUFILES) +endif +ifneq ($(CLEANPPULINKFILES),) + -$(DEL) $(CLEANPPULINKFILES) +endif +ifdef CLEANRSTFILES + -$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES)) +endif +endif +ifdef CLEAN_FILES + -$(DEL) $(CLEAN_FILES) +endif + -$(DELTREE) units + -$(DELTREE) bin + -$(DEL) *$(OEXT) *$(LTOEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT) +ifneq ($(PPUEXT),.ppu) + -$(DEL) *.o *.ppu *.a +endif + -$(DELTREE) *$(SMARTEXT) + -$(DEL) fpcmade.* Package.fpc *.fpm + -$(DEL) $(FPCEXTFILE) $(REDIRFILE) script*.res link*.res *_script.res *_link.res + -$(DEL) $(PPAS) *_ppas$(BATCHEXT) ppas$(BATCHEXT) ppaslink$(BATCHEXT) +ifdef AOUTEXT + -$(DEL) *$(AOUTEXT) +endif +ifdef DEBUGSYMEXT + -$(DEL) *$(DEBUGSYMEXT) +endif +ifdef LOCALFPMAKEBIN + -$(DEL) $(LOCALFPMAKEBIN) + -$(DEL) $(FPMAKEBINOBJ) +endif +fpc_distclean: cleanall +.PHONY: fpc_baseinfo +override INFORULES+=fpc_baseinfo +fpc_baseinfo: + @$(ECHO) + @$(ECHO) == Package info == + @$(ECHO) Package Name..... $(PACKAGE_NAME) + @$(ECHO) Package Version.. $(PACKAGE_VERSION) + @$(ECHO) + @$(ECHO) == Configuration info == + @$(ECHO) + @$(ECHO) FPC.......... $(FPC) + @$(ECHO) FPC Version.. $(FPC_VERSION) + @$(ECHO) Source CPU... $(CPU_SOURCE) + @$(ECHO) Target CPU... $(CPU_TARGET) + @$(ECHO) Source OS.... $(OS_SOURCE) + @$(ECHO) Target OS.... $(OS_TARGET) + @$(ECHO) Full Source.. $(FULL_SOURCE) + @$(ECHO) Full Target.. $(FULL_TARGET) + @$(ECHO) SourceSuffix. $(SOURCESUFFIX) + @$(ECHO) TargetSuffix. $(TARGETSUFFIX) + @$(ECHO) FPC fpmake... $(FPCFPMAKE) + @$(ECHO) + @$(ECHO) == Directory info == + @$(ECHO) + @$(ECHO) Required pkgs... $(REQUIRE_PACKAGES) + @$(ECHO) + @$(ECHO) Basedir......... $(BASEDIR) + @$(ECHO) FPCDir.......... $(FPCDIR) + @$(ECHO) CrossBinDir..... $(CROSSBINDIR) + @$(ECHO) UnitsDir........ $(UNITSDIR) + @$(ECHO) PackagesDir..... $(PACKAGESDIR) + @$(ECHO) + @$(ECHO) GCC library..... $(GCCLIBDIR) + @$(ECHO) Other library... $(OTHERLIBDIR) + @$(ECHO) + @$(ECHO) == Tools info == + @$(ECHO) + @$(ECHO) As........ $(AS) + @$(ECHO) Ld........ $(LD) + @$(ECHO) Ar........ $(AR) + @$(ECHO) Rc........ $(RC) + @$(ECHO) + @$(ECHO) Mv........ $(MVPROG) + @$(ECHO) Cp........ $(CPPROG) + @$(ECHO) Rm........ $(RMPROG) + @$(ECHO) GInstall.. $(GINSTALL) + @$(ECHO) Echo...... $(ECHO) + @$(ECHO) Shell..... $(SHELL) + @$(ECHO) Date...... $(DATE) + @$(ECHO) FPCMake... $(FPCMAKE) + @$(ECHO) PPUMove... $(PPUMOVE) + @$(ECHO) Zip....... $(ZIPPROG) + @$(ECHO) + @$(ECHO) == Object info == + @$(ECHO) + @$(ECHO) Target Loaders........ $(TARGET_LOADERS) + @$(ECHO) Target Units.......... $(TARGET_UNITS) + @$(ECHO) Target Implicit Units. $(TARGET_IMPLICITUNITS) + @$(ECHO) Target Programs....... $(TARGET_PROGRAMS) + @$(ECHO) Target Dirs........... $(TARGET_DIRS) + @$(ECHO) Target Examples....... $(TARGET_EXAMPLES) + @$(ECHO) Target ExampleDirs.... $(TARGET_EXAMPLEDIRS) + @$(ECHO) + @$(ECHO) Clean Units......... $(CLEAN_UNITS) + @$(ECHO) Clean Files......... $(CLEAN_FILES) + @$(ECHO) + @$(ECHO) Install Units....... $(INSTALL_UNITS) + @$(ECHO) Install Files....... $(INSTALL_FILES) + @$(ECHO) + @$(ECHO) == Install info == + @$(ECHO) + @$(ECHO) DateStr.............. $(DATESTR) + @$(ECHO) ZipName.............. $(ZIPNAME) + @$(ECHO) ZipPrefix............ $(ZIPPREFIX) + @$(ECHO) ZipCrossPrefix....... $(ZIPCROSSPREFIX) + @$(ECHO) ZipSuffix............ $(ZIPSUFFIX) + @$(ECHO) FullZipName.......... $(FULLZIPNAME) + @$(ECHO) Install FPC Package.. $(INSTALL_FPCPACKAGE) + @$(ECHO) + @$(ECHO) Install base dir..... $(INSTALL_BASEDIR) + @$(ECHO) Install binary dir... $(INSTALL_BINDIR) + @$(ECHO) Install library dir.. $(INSTALL_LIBDIR) + @$(ECHO) Install units dir.... $(INSTALL_UNITDIR) + @$(ECHO) Install source dir... $(INSTALL_SOURCEDIR) + @$(ECHO) Install doc dir...... $(INSTALL_DOCDIR) + @$(ECHO) Install example dir.. $(INSTALL_EXAMPLEDIR) + @$(ECHO) Install data dir..... $(INSTALL_DATADIR) + @$(ECHO) + @$(ECHO) Dist destination dir. $(DIST_DESTDIR) + @$(ECHO) Dist zip name........ $(DIST_ZIPNAME) + @$(ECHO) +.PHONY: fpc_info +fpc_info: $(INFORULES) +.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \ + fpc_makefile_dirs +fpc_makefile: + $(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc +fpc_makefile_sub1: +ifdef TARGET_DIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS)) +endif +ifdef TARGET_EXAMPLEDIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS)) +endif +fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS)) +fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2 +fpc_makefiles: fpc_makefile fpc_makefile_dirs +units: +examples: +shared: +sourceinstall: fpc_sourceinstall +exampleinstall: fpc_exampleinstall +zipexampleinstall: fpc_zipexampleinstall +info: fpc_info +makefiles: fpc_makefiles +.PHONY: units examples shared sourceinstall exampleinstall zipexampleinstall info makefiles +ifneq ($(wildcard fpcmake.loc),) +include fpcmake.loc +endif +override FPCOPT:=$(filter-out -FU%,$(FPCOPT)) +override FPCOPT:=$(filter-out -FE%,$(FPCOPT)) +override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters +ifdef FPMAKEOPT +FPMAKE_OPT+=$(FPMAKEOPT) +endif +FPMAKE_OPT+=--localunitdir=../.. +FPMAKE_OPT+=--globalunitdir=.. +FPMAKE_OPT+=$(FPC_TARGETOPT) +FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT)) +FPMAKE_OPT+=--compiler=$(FPC) +FPMAKE_OPT+=-bu +.NOTPARALLEL: +fpmake$(SRCEXEEXT): fpmake.pp + $(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT) +all: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) +smart: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX +release: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE +debug: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG +ifeq ($(FPMAKE_BIN_CLEAN),) +clean: +else +clean: + $(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT) +endif +ifeq ($(FPMAKE_BIN_CLEAN),) +distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall +else +distclean: +ifdef inUnix + { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; } +else + $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT) +endif + -$(DEL) $(LOCALFPMAKE) +endif +cleanall: distclean +install: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) +endif +distinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +endif +zipinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) +zipdistinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0 +zipsourceinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\) +else + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\) +endif diff --git a/packages/fcl-mustache/Makefile.fpc b/packages/fcl-mustache/Makefile.fpc new file mode 100644 index 0000000000..be05c3c7c9 --- /dev/null +++ b/packages/fcl-mustache/Makefile.fpc @@ -0,0 +1,128 @@ +# +# Makefile.fpc for running fpmake +# + +[package] +name=fcl-mustache +version=3.3.1 + +[require] +packages=rtl fcl-base fcl-db fcl-json + +[install] +fpcpackage=y + +[default] +fpcdir=../.. + +[prerules] +FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT)) +ifdef OS_TARGET +FPC_TARGETOPT+=--os=$(OS_TARGET) +endif +ifdef CPU_TARGET +FPC_TARGETOPT+=--cpu=$(CPU_TARGET) +endif +LOCALFPMAKE=./fpmake$(SRCEXEEXT) +# Adding a dependency on fpmkunit is not possbile due to an infinite loop. So +# the fpmkunit-searchpath is added here: +PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FPMKUNIT),) +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE) +endif +else +PACKAGEDIR_FPMKUNIT= +UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FPMKUNIT),) +UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT)) +else +UNITDIR_FPMKUNIT= +endif +endif +ifdef UNITDIR_FPMAKE_FPMKUNIT +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT) +endif + +[rules] +# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own. +override FPCOPT:=$(filter-out -FU%,$(FPCOPT)) +override FPCOPT:=$(filter-out -FE%,$(FPCOPT)) +# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm +override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters +# Compose general fpmake-parameters +ifdef FPMAKEOPT +FPMAKE_OPT+=$(FPMAKEOPT) +endif +FPMAKE_OPT+=--localunitdir=../.. +FPMAKE_OPT+=--globalunitdir=.. +FPMAKE_OPT+=$(FPC_TARGETOPT) +FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT)) +FPMAKE_OPT+=--compiler=$(FPC) +FPMAKE_OPT+=-bu +.NOTPARALLEL: + +fpmake$(SRCEXEEXT): fpmake.pp + $(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT) +all: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) +smart: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX +release: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE +debug: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG +# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will +# most often fail because the dependencies are cleared. +# In case of a clean, simply do nothing +ifeq ($(FPMAKE_BIN_CLEAN),) +clean: +else +clean: + $(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT) +endif +# In case of a distclean, perform an 'old'-style distclean. This to avoid problems +# when the package is compiled using fpcmake prior to running this clean using fpmake +ifeq ($(FPMAKE_BIN_CLEAN),) +distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall +else +distclean: +ifdef inUnix + { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; } +else + $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT) +endif + -$(DEL) $(LOCALFPMAKE) +endif +cleanall: distclean +install: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) +endif +# distinstall also installs the example-sources and omits the location of the source- +# files from the fpunits.cfg files. +distinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +endif +zipinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) +zipdistinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0 +zipsourceinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\) +else + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\) +endif diff --git a/packages/fcl-mustache/fpmake.pp b/packages/fcl-mustache/fpmake.pp new file mode 100644 index 0000000000..4457240c05 --- /dev/null +++ b/packages/fcl-mustache/fpmake.pp @@ -0,0 +1,49 @@ +{$ifndef ALLPACKAGES} +{$mode objfpc}{$H+} +program fpmake; + +uses fpmkunit; + +Var + P : TPackage; + T : TTarget; +begin + With Installer do + begin +{$endif ALLPACKAGES} + P:=AddPackage('fcl-mustache'); + P.ShortName:='mustache'; + +{$ifdef ALLPACKAGES} + P.Directory:=ADirectory; +{$endif ALLPACKAGES} + + P.Author := 'Michael Van Canneyt'; + P.License := 'LGPL with modification, '; + P.HomepageURL := 'www.freepascal.org'; + P.Email := ''; + P.Description := 'Mustache templates for FPC'; + P.NeedLibC:= false; + P.SourcePath.Add('src'); + P.OSes:=P.OSes-[embedded,win16,msdos,nativent,macosclassic,palmos,zxspectrum,msxdos,amstradcpc,sinclairql,wasi]; + if Defaults.CPU=jvm then + P.OSes := P.OSes - [java,android]; + + P.Dependencies.Add('rtl-objpas'); + P.Dependencies.Add('fcl-base'); + P.Dependencies.Add('fcl-json'); + P.Dependencies.Add('fcl-db'); + P.Version:='3.3.1'; + T:=P.Targets.AddUnit('src/fpmustache.pp'); + T.ResourceStrings:=true; + T:=P.Targets.AddUnit('src/fpdbmustache.pp'); + T.ResourceStrings:=true; + T.Dependencies.AddUnit('fpmustache'); + T:=P.Targets.AddUnit('src/fpexmustache.pp'); + T.ResourceStrings:=true; + T.Dependencies.AddUnit('fpmustache'); +{$ifndef ALLPACKAGES} + Run; + end; +end. +{$endif ALLPACKAGES} -- cgit v1.2.1 From de2e3396159b746f3a9178a59b144ce9cd1c06fd Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Wed, 21 Apr 2021 19:51:22 +0000 Subject: * moved warning about suspicious comp assignment to type check pass, catches also assignments of constants git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49242 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/ncnv.pas | 4 ++++ compiler/x86/nx86cnv.pas | 5 ----- tests/tbf/tb0274.pp | 8 ++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tests/tbf/tb0274.pp diff --git a/compiler/ncnv.pas b/compiler/ncnv.pas index f115685a3d..5f5cb3f4cb 100644 --- a/compiler/ncnv.pas +++ b/compiler/ncnv.pas @@ -1630,6 +1630,10 @@ implementation include(flags,nf_is_currency); typecheckpass(left); end; + { comp is handled by the fpu but not a floating type point } + if is_fpucomp(resultdef) and not(is_fpucomp(left.resultdef)) and + not (nf_explicit in flags) then + Message(type_w_convert_real_2_comp); end else include(flags,nf_is_currency); diff --git a/compiler/x86/nx86cnv.pas b/compiler/x86/nx86cnv.pas index 91ea652eb4..805c8c5a96 100644 --- a/compiler/x86/nx86cnv.pas +++ b/compiler/x86/nx86cnv.pas @@ -72,11 +72,6 @@ implementation function tx86typeconvnode.first_real_to_real : tnode; begin first_real_to_real:=nil; - { comp isn't a floating type } - if (tfloatdef(resultdef).floattype=s64comp) and - (tfloatdef(left.resultdef).floattype<>s64comp) and - not (nf_explicit in flags) then - CGMessage(type_w_convert_real_2_comp); if use_vectorfpu(resultdef) then expectloc:=LOC_MMREGISTER else diff --git a/tests/tbf/tb0274.pp b/tests/tbf/tb0274.pp new file mode 100644 index 0000000000..4749726510 --- /dev/null +++ b/tests/tbf/tb0274.pp @@ -0,0 +1,8 @@ +{ %fail } +{ %opt=-Sew } +var + c : comp; + +begin + c:=123.123; +end. -- cgit v1.2.1 From d7efd1db7e2da4157afc0a06fa76eadccfff021d Mon Sep 17 00:00:00 2001 From: marco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Thu, 22 Apr 2021 14:00:51 +0000 Subject: * use W variant to get localestrs. git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49244 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/win/sysutils.pp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rtl/win/sysutils.pp b/rtl/win/sysutils.pp index 726b389fe2..594fc0abfc 100644 --- a/rtl/win/sysutils.pp +++ b/rtl/win/sysutils.pp @@ -1037,14 +1037,18 @@ end; Locale Functions ****************************************************************************} -function GetLocaleStr(LID, LT: Longint; const Def: string): ShortString; +function GetLocaleStr(LID, LT: Longint; const Def: string): AnsiString; var L: Integer; - Buf: array[0..255] of Char; + Buf: unicodestring; begin - L := GetLocaleInfoA(LID, LT, Buf, SizeOf(Buf)); + L := GetLocaleInfoW(LID, LT, nil, 0); if L > 0 then - SetString(Result, @Buf[0], L - 1) + begin + SetLength(Buf,L-1); // L includes terminating NULL + L := GetLocaleInfoW(LID, LT, @Buf[1], L); + result:=buf; + end else Result := Def; end; -- cgit v1.2.1 From 9362a5c2838eb44563f596367d58116266516c35 Mon Sep 17 00:00:00 2001 From: marco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Thu, 22 Apr 2021 15:11:38 +0000 Subject: * patch by Wallaby, mantis 0038382, load filename via -W function git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49245 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/winunits-base/src/comserv.pp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/winunits-base/src/comserv.pp b/packages/winunits-base/src/comserv.pp index d81adc8768..522b6e8ad9 100644 --- a/packages/winunits-base/src/comserv.pp +++ b/packages/winunits-base/src/comserv.pp @@ -205,9 +205,12 @@ end; function GetModuleFileName: String; const MAX_PATH_SIZE = 2048; +var + FileName: WideString; begin - SetLength(Result, MAX_PATH_SIZE); - SetLength(Result, Windows.GetModuleFileName(HInstance, @Result[1], MAX_PATH_SIZE)); + SetLength(FileName, MAX_PATH_SIZE); + SetLength(FileName, Windows.GetModuleFileNameW(HInstance, @FileName[1], MAX_PATH_SIZE)); + Result := FileName; end; function GetModuleName: String; -- cgit v1.2.1 From 622af098008dc21b62c0577ba6435e872052555d Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Thu, 22 Apr 2021 15:26:15 +0000 Subject: Remove unused, obsolete -dBROWSERLOG option git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49246 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/MPWMake | 2 +- compiler/Makefile | 2 +- compiler/Makefile.fpc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/MPWMake b/compiler/MPWMake index 8591f382fc..90ce41fe10 100644 --- a/compiler/MPWMake +++ b/compiler/MPWMake @@ -1 +1 @@ -# Make file for MPW make. # To run it, use: # Make <target> -f MPWMake > Makeout ; Makeout # where <target> should be replaced with actual make target. ############################################# # TIPS (TODO move to Wiki or something # # Defined variables: No quoting # Command lines: quote paths, dont quote option strings, since # they might contain several options, which must be separated. # Recursive call to Make: # - give options as -d XXX="{XXX}" # - in same dir, remember to ensure to have different Makeout files, # e g Makeout2. # # NOTE Currently cycle is stopped after three rounds, no diff is checked. FPC = {FPCDIR}bin:ppcppc # Default language for the compiler (english): FPCLANG = e MSGFILE = :msg:error{FPCLANG}.msg msg2inc Ä :utils:msg2inc.pp {FPC} -FE: -WT :utils:msg2inc.pp # The msgtxt.inc only depends on the error?.msg file, not on msg2inc, # because that one will be new almost everytime msgtxt.inc Ä {MSGFILE} Make msg2inc -f MPWMake > Makeout3 ; Makeout3 msg2inc {MSGFILE} msg msg msg Ä msgtxt.inc compiler Ä msg Set Exit 0 NewFolder :powerpc:units: ³ Dev:Null NewFolder :powerpc:units:powerpc-macos: ³ Dev:Null Set Exit 1 "{FPC}" {OPT} "-Fu{RTLDIR}" -Fu:systems: -Fu:powerpc: -Fu:ppcgen -dGDB -dBROWSERLOG -dNOOPT ¶ -dpowerpc -WT -FE: -FU:powerpc:units:powerpc-macos: pp.pas Rename -y pp ppcppc clean Ä utils_clean Set Exit 0 Delete -y :powerpc:units:powerpc-macos Delete -y ppcppc oldfpc msg2inc Delete -y Å.xcoff Set Exit 1 cycleclean Ä Set Exit 0 Delete -y :powerpc:units:powerpc-macos Set Exit 1 install Ä If {FPCDIR} == '' Set -e FPCDIR `GetFileName -wd -m 'Select where to install the FreePascal folder'`FreePascal: Set -e Commands "{Commands},{FPCDIR}bin:" Echo "Set -e FPCDIR ¶'{FPCDIR}¶'" > "{MPW}Startup Items:FPC Startup" Echo 'Set -e Commands "{Commands},{FPCDIR}bin:"' >> "{MPW}Startup Items:FPC Startup" End Set Exit 0 NewFolder "{FPCDIR}" ³ Dev:Null NewFolder "{FPCDIR}bin:" ³ Dev:Null Set Exit 1 Duplicate -y :ppcppc :utils:ppudump :utils:ppufiles :utils:ppumove ¶ :utils:fpc "{FPCDIR}bin:" Echo "# Configuration file for Free Pascal for MPW" > "{FPCDIR}bin:fpc.cfg" Echo "-Fu¶'{FPCDIR}units:rtl:¶'" >> "{FPCDIR}bin:fpc.cfg" Echo "-l" >> "{FPCDIR}bin:fpc.cfg" Echo "-vi" >> "{FPCDIR}bin:fpc.cfg" cycle Ä Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC="{FPC}" -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make clean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC="{FPC}" -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Echo '******************** SECOND ROUND *********************' Rename -y ppcppc oldfpc Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC=:::compiler:oldfpc -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make cycleclean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC=oldfpc -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Echo '********************* THIRD ROUND *********************' Rename -y ppcppc oldfpc Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC=:::compiler:oldfpc -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make cycleclean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC=oldfpc -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Make utils_clean -f MPWMake > Makeout2 ; Makeout2 Make utils_all -d FPC=::oldfpc -d OPT="{OPT}" -d RTLDIR=:::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 utils_all Ä Directory :utils Set Exit 0 NewFolder :units: ³ Dev:Null NewFolder :units:powerpc-macos: ³ Dev:Null Set Exit 1 "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppudump.pp "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppufiles.pp "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppumove.pp Duplicate -y fpc.mpw fpc Directory :: utils_clean Ä Directory :utils Set Exit 0 Delete -y :units:powerpc-macos Delete -y fpc ppudump ppufiles ppumove msg2inc Delete -y Å.xcoff Set Exit 1 Directory :: \ No newline at end of file +# Make file for MPW make. # To run it, use: # Make <target> -f MPWMake > Makeout ; Makeout # where <target> should be replaced with actual make target. ############################################# # TIPS (TODO move to Wiki or something # # Defined variables: No quoting # Command lines: quote paths, dont quote option strings, since # they might contain several options, which must be separated. # Recursive call to Make: # - give options as -d XXX="{XXX}" # - in same dir, remember to ensure to have different Makeout files, # e g Makeout2. # # NOTE Currently cycle is stopped after three rounds, no diff is checked. FPC = {FPCDIR}bin:ppcppc # Default language for the compiler (english): FPCLANG = e MSGFILE = :msg:error{FPCLANG}.msg msg2inc Ä :utils:msg2inc.pp {FPC} -FE: -WT :utils:msg2inc.pp # The msgtxt.inc only depends on the error?.msg file, not on msg2inc, # because that one will be new almost everytime msgtxt.inc Ä {MSGFILE} Make msg2inc -f MPWMake > Makeout3 ; Makeout3 msg2inc {MSGFILE} msg msg msg Ä msgtxt.inc compiler Ä msg Set Exit 0 NewFolder :powerpc:units: ³ Dev:Null NewFolder :powerpc:units:powerpc-macos: ³ Dev:Null Set Exit 1 "{FPC}" {OPT} "-Fu{RTLDIR}" -Fu:systems: -Fu:powerpc: -Fu:ppcgen -dGDB -dNOOPT ¶ -dpowerpc -WT -FE: -FU:powerpc:units:powerpc-macos: pp.pas Rename -y pp ppcppc clean Ä utils_clean Set Exit 0 Delete -y :powerpc:units:powerpc-macos Delete -y ppcppc oldfpc msg2inc Delete -y Å.xcoff Set Exit 1 cycleclean Ä Set Exit 0 Delete -y :powerpc:units:powerpc-macos Set Exit 1 install Ä If {FPCDIR} == '' Set -e FPCDIR `GetFileName -wd -m 'Select where to install the FreePascal folder'`FreePascal: Set -e Commands "{Commands},{FPCDIR}bin:" Echo "Set -e FPCDIR ¶'{FPCDIR}¶'" > "{MPW}Startup Items:FPC Startup" Echo 'Set -e Commands "{Commands},{FPCDIR}bin:"' >> "{MPW}Startup Items:FPC Startup" End Set Exit 0 NewFolder "{FPCDIR}" ³ Dev:Null NewFolder "{FPCDIR}bin:" ³ Dev:Null Set Exit 1 Duplicate -y :ppcppc :utils:ppudump :utils:ppufiles :utils:ppumove ¶ :utils:fpc "{FPCDIR}bin:" Echo "# Configuration file for Free Pascal for MPW" > "{FPCDIR}bin:fpc.cfg" Echo "-Fu¶'{FPCDIR}units:rtl:¶'" >> "{FPCDIR}bin:fpc.cfg" Echo "-l" >> "{FPCDIR}bin:fpc.cfg" Echo "-vi" >> "{FPCDIR}bin:fpc.cfg" cycle Ä Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC="{FPC}" -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make clean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC="{FPC}" -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Echo '******************** SECOND ROUND *********************' Rename -y ppcppc oldfpc Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC=:::compiler:oldfpc -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make cycleclean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC=oldfpc -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Echo '********************* THIRD ROUND *********************' Rename -y ppcppc oldfpc Directory ::rtl:macos Make clean -f MPWMake > Makeout ; Makeout Make all -d FPC=:::compiler:oldfpc -d OPT="{OPT}" -f MPWMake > Makeout ; Makeout Directory :::compiler Make cycleclean -f MPWMake > Makeout2 ; Makeout2 Make compiler -d FPC=oldfpc -d OPT="{OPT}" -d RTLDIR=::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 # Make utils_clean -f MPWMake > Makeout2 ; Makeout2 Make utils_all -d FPC=::oldfpc -d OPT="{OPT}" -d RTLDIR=:::rtl:units:powerpc-macos -f MPWMake > Makeout2 ; Makeout2 utils_all Ä Directory :utils Set Exit 0 NewFolder :units: ³ Dev:Null NewFolder :units:powerpc-macos: ³ Dev:Null Set Exit 1 "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppudump.pp "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppufiles.pp "{FPC}" {OPT} "-Fu{RTLDIR}" -FE: -FU:units:powerpc-macos -Fu:: -WT ppumove.pp Duplicate -y fpc.mpw fpc Directory :: utils_clean Ä Directory :utils Set Exit 0 Delete -y :units:powerpc-macos Delete -y fpc ppudump ppufiles ppumove msg2inc Delete -y Å.xcoff Set Exit 1 Directory :: diff --git a/compiler/Makefile b/compiler/Makefile index f19c59109b..ffc63cc2b8 100644 --- a/compiler/Makefile +++ b/compiler/Makefile @@ -581,7 +581,7 @@ endif endif endif endif -override LOCALOPT+=-d$(CPC_TARGET) -dGDB -dBROWSERLOG +override LOCALOPT+=-d$(CPC_TARGET) -dGDB ifdef LLVM ifeq ($(findstring $(PPC_TARGET),x86_64 aarch64 arm),) $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM code generator) diff --git a/compiler/Makefile.fpc b/compiler/Makefile.fpc index 7082b7d7e9..7d484654bc 100644 --- a/compiler/Makefile.fpc +++ b/compiler/Makefile.fpc @@ -323,7 +323,7 @@ endif endif # set correct defines (-d$(CPU_TARGET) is automatically added in makefile.fpc) -override LOCALOPT+=-d$(CPC_TARGET) -dGDB -dBROWSERLOG +override LOCALOPT+=-d$(CPC_TARGET) -dGDB #include LLVM define/directory if requested ifdef LLVM -- cgit v1.2.1 From 16cbe36ee0b8e05bd4b88f35ad237cb2c6ba54aa Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Thu, 22 Apr 2021 20:14:00 +0000 Subject: * fixed MSecsToTimeStamp by Lagunov Aleksey, resolves #38631 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49247 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/objpas/sysutils/dati.inc | 12 +++++++----- tests/webtbs/tw38631.pp | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/webtbs/tw38631.pp diff --git a/rtl/objpas/sysutils/dati.inc b/rtl/objpas/sysutils/dati.inc index 19848e57bf..667d7c1360 100644 --- a/rtl/objpas/sysutils/dati.inc +++ b/rtl/objpas/sysutils/dati.inc @@ -75,18 +75,20 @@ end; { MSecsToTimeStamp } function MSecsToTimeStamp(MSecs: comp): TTimeStamp; +var + D1:Int64; begin - result.Date := Trunc(msecs / msecsperday); - msecs:= msecs-comp(result.date)*msecsperday; - result.Time := Round(MSecs); -end ; + D1:=Trunc(msecs); + result.Date := D1 div msecsperday; + result.Time := D1 - result.date * msecsperday; +end; { TimeStampToMSecs } function TimeStampToMSecs(const TimeStamp: TTimeStamp): comp; begin result := TimeStamp.Time + comp(timestamp.date)*msecsperday; -end ; +end; Function TryEncodeDate(Year,Month,Day : Word; Out Date : TDateTime) : Boolean; diff --git a/tests/webtbs/tw38631.pp b/tests/webtbs/tw38631.pp new file mode 100644 index 0000000000..76448e4516 --- /dev/null +++ b/tests/webtbs/tw38631.pp @@ -0,0 +1,23 @@ +{$mode objfpc} +program msec_test1; +uses sysutils; + +var + D: TDateTime; + T, T1, T2: TTimeStamp; + MS: Comp; +begin + D:=EncodeDate(2021, 03, 16) + EncodeTime(14, 02, 15, 1); + WriteLn('DATE: ', DateTimeToStr(D)); + + T:=DateTimeToTimeStamp(D); + WriteLn(' T.Date=',T.Date,' T.Time=', T.Time); + MS:=TimeStampToMSecs(T); + T1:=MSecsToTimeStamp(MS); + WriteLn('T1.Date=',T1.Date,' T1.Time=', T1.Time); + + WriteLn('DATE1: ', DateTimeToStr(TimeStampToDateTime(T1))); + if TimeStampToDateTime(T1)<>D then + halt(1); + writeln('ok') +end. -- cgit v1.2.1 From 93130e2031ad16651434d06955089251ba704995 Mon Sep 17 00:00:00 2001 From: svenbarth <svenbarth@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Fri, 23 Apr 2021 14:05:21 +0000 Subject: * NDS: fix condition when to default to apptype arm9 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49248 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/systems/t_nds.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/systems/t_nds.pas b/compiler/systems/t_nds.pas index 2ee6a516cd..1cc0afb5fd 100644 --- a/compiler/systems/t_nds.pas +++ b/compiler/systems/t_nds.pas @@ -57,7 +57,7 @@ begin SharedLibFiles.doubles:=true; StaticLibFiles.doubles:=true; // set arm9 as default apptype - if (apptype <> app_arm9) or (apptype <> app_arm7) then + if (apptype <> app_arm9) and (apptype <> app_arm7) then apptype:=app_arm9; end; -- cgit v1.2.1 From bee20fdc6c1055b6140d1976a586b1b1b04370d2 Mon Sep 17 00:00:00 2001 From: svenbarth <svenbarth@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Fri, 23 Apr 2021 14:05:23 +0000 Subject: * use $IF DEFINED instead of $IFDEF for consistency (and is required for 3.2.2) git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49249 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/openssl/src/openssl.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/openssl/src/openssl.pas b/packages/openssl/src/openssl.pas index 8c6ec08af4..3dfe068495 100644 --- a/packages/openssl/src/openssl.pas +++ b/packages/openssl/src/openssl.pas @@ -90,7 +90,7 @@ Type const // SSL and Crypto DLL arrays must have the same length and contain // matched pairs of DLL filenames. Place newer versions at the beginning. -{$IFDEF WIN64} +{$IF DEFINED(WIN64)} SSL_DLL_Names: array[1..3] of string = ('libssl-1_1-x64', 'ssleay32', 'libssl32'); Crypto_DLL_Names: array[1..3] of string = ('libcrypto-1_1-x64', 'libeay32', 'libeay32'); {$ELSEIF DEFINED(WINDOWS)} -- cgit v1.2.1 From e6ca7987ef6521c3545105539e51ff9d41dfad43 Mon Sep 17 00:00:00 2001 From: marco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Fri, 23 Apr 2021 19:06:18 +0000 Subject: * avoid rangecheck mantis 0038791 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49250 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/win/sysutils.pp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtl/win/sysutils.pp b/rtl/win/sysutils.pp index 594fc0abfc..2776b5e135 100644 --- a/rtl/win/sysutils.pp +++ b/rtl/win/sysutils.pp @@ -1046,7 +1046,8 @@ begin if L > 0 then begin SetLength(Buf,L-1); // L includes terminating NULL - L := GetLocaleInfoW(LID, LT, @Buf[1], L); + if l>1 Then + L := GetLocaleInfoW(LID, LT, @Buf[1], L); result:=buf; end else -- cgit v1.2.1 From 1f14917378faf6214b3241600f290d79e4b278fb Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Fri, 23 Apr 2021 21:16:16 +0000 Subject: * improved system unit dependencies git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49251 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/darwin/Makefile | 2 +- rtl/darwin/Makefile.fpc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtl/darwin/Makefile b/rtl/darwin/Makefile index ec43154a29..18ad8c7628 100644 --- a/rtl/darwin/Makefile +++ b/rtl/darwin/Makefile @@ -3293,7 +3293,7 @@ include $(INC)/makefile.inc SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES)) include $(PROCINC)/makefile.cpu SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES)) -SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) +SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) sighnd.inc sig_cpu.inc $(SYSTEMUNIT)$(PPUEXT) : $(BSDINC)/$(SYSTEMUNIT).pp $(SYSDEPS) $(COMPILER) $(FPC_SYSTEM_OPT) -Us -Sg $(BSDINC)/$(SYSTEMUNIT).pp sysinit$(PPUEXT) : sysinit.pas $(SYSTEMUNIT)$(PPUEXT) diff --git a/rtl/darwin/Makefile.fpc b/rtl/darwin/Makefile.fpc index 1a0e19d6a3..42a2ebaa9d 100644 --- a/rtl/darwin/Makefile.fpc +++ b/rtl/darwin/Makefile.fpc @@ -116,7 +116,7 @@ include $(PROCINC)/makefile.cpu SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES)) # Put system unit dependencies together. -SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) +SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) sighnd.inc sig_cpu.inc # -- cgit v1.2.1 From 16ed3e2dca27a0ad4100396b4d2bf967bbe3bd91 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Fri, 23 Apr 2021 21:52:24 +0000 Subject: Fix gotpcrel relocation for TESTQ x86_64 instruction git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49252 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/ogelf.pas | 5 ++++- compiler/x86/aasmcpu.pas | 10 ++++++++++ tests/webtbs/tw38353.pp | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/webtbs/tw38353.pp diff --git a/compiler/ogelf.pas b/compiler/ogelf.pas index bb77186427..e21123c8c6 100644 --- a/compiler/ogelf.pas +++ b/compiler/ogelf.pas @@ -672,7 +672,10 @@ implementation if assigned(objreloc) then begin objreloc.size:=len; - if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_TLSGD,RELOC_GOTPCREL{$endif}] then + { RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX] need special handling + this is done in x86/aasmcpu unit } + if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif} + {$ifdef x86_64}, RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX,RELOC_TLSGD{$endif}] then dec(data,len); if ElfTarget.relocs_use_addend then begin diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 43ed8b4fd2..41f57dad9d 100644 --- a/compiler/x86/aasmcpu.pas +++ b/compiler/x86/aasmcpu.pas @@ -3682,6 +3682,16 @@ implementation end; {$endif i386} objdata.writereloc(data,len,p,Reloctype); +{$ifdef x86_64} + { Computed offset is not yet correct for GOTPC relocation } + { RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX need special handling } + if assigned(p) and (RelocType in [RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX]) and + { These relocations seem to be used only for ELF + which always has relocs_use_addend set to true + so that it is the orgsize of the last relocation which needs to be fixed PM } + (insend<>objdata.CurrObjSec.size) then + dec(TObjRelocation(objdata.CurrObjSec.ObjRelocations.Last).orgsize,insend-objdata.CurrObjSec.size); +{$endif} end; diff --git a/tests/webtbs/tw38353.pp b/tests/webtbs/tw38353.pp new file mode 100644 index 0000000000..2d57fbe30a --- /dev/null +++ b/tests/webtbs/tw38353.pp @@ -0,0 +1,42 @@ +{ %OPT=-Cg -O2 } +{ %CPU=x86_64 } + +{ -Cg and -O2 options together lead to + the generation of instruction: + testq $15,U_$P$VECTORCALL_HVA_TEST1_$$_HVA@GOTPCREL(%rip) + for which the relocation was not correctly generated + in the internal assembler } + +program tw38353; + +{$IFNDEF CPUX86_64} + {$FATAL This test program can only be compiled on Windows or Linux 64-bit with an Intel processor } +{$ENDIF} + +{$ASMMODE Intel} +{$PUSH} +{$CODEALIGN RECORDMIN=16} +{$PACKRECORDS C} +type + TM128 = record + case Byte of + 0: (M128_F32: array[0..3] of Single); + 1: (M128_F64: array[0..1] of Double); + end; +{$POP} + +var + HVA: TM128; + +begin +{$ifdef verbose} + writeln('@HVA=',hexstr(ptruint(@HVA),2*sizeof(ptruint))); +{$endif verbose} + if (PtrUInt(@HVA) and $F) <> 0 then + begin +{$ifdef verbose} + WriteLn('FAIL: HVA is not correctly aligned.'); +{$endif verbose} + Halt(1); + end; +end. -- cgit v1.2.1 From 46654882fa21eb8cd56ca1720cf81c265a75bb7e Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 10:55:03 +0000 Subject: pastojs: specialize try except on, issue 38795 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49253 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-passrc/tests/tcresolvegenerics.pas | 1 + packages/pastojs/src/fppas2js.pp | 5 +- packages/pastojs/tests/tcgenerics.pas | 72 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/packages/fcl-passrc/tests/tcresolvegenerics.pas b/packages/fcl-passrc/tests/tcresolvegenerics.pas index 83f59c6c7c..8c39552070 100644 --- a/packages/fcl-passrc/tests/tcresolvegenerics.pas +++ b/packages/fcl-passrc/tests/tcresolvegenerics.pas @@ -157,6 +157,7 @@ type procedure TestGenProc_TypeParamCntOverloadNoParams; procedure TestGenProc_TypeParamWithDefaultParamDelphiFail; procedure TestGenProc_ParamSpecWithT; + // ToDo: TestGenProc_ParamSpecWithTNestedType function Fly<T>(a: TBird<T>.TEvent; aSender: T): Word; // ToDo: NestedResultAssign // generic function infer types diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index bb222fd720..2054885b0d 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -4488,6 +4488,9 @@ begin AddElevatedLocal(El); end; end + else if ParentC=TPasImplExceptOn then + // except on var + RaiseVarModifierNotSupported(LocalVarModifiersAllowed) else if ParentC=TImplementationSection then // implementation var RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed) @@ -4499,7 +4502,7 @@ begin else begin {$IFDEF VerbosePas2JS} - writeln('TPas2JSResolver.FinishVariable ',GetObjName(El),' Parent=',GetObjName(El.Parent)); + writeln('TPas2JSResolver.FinishVariable ',GetObjPath(El)); {$ENDIF} RaiseNotYetImplemented(20170324151259,El); end; diff --git a/packages/pastojs/tests/tcgenerics.pas b/packages/pastojs/tests/tcgenerics.pas index 8b1c961aa3..ff46fbe342 100644 --- a/packages/pastojs/tests/tcgenerics.pas +++ b/packages/pastojs/tests/tcgenerics.pas @@ -62,6 +62,7 @@ type Procedure TestGen_CallUnitImplProc; Procedure TestGen_IntAssignTemplVar; Procedure TestGen_TypeCastDotField; + Procedure TestGen_Except; // generic helper procedure TestGen_HelperForArray; @@ -1950,6 +1951,77 @@ begin ''])); end; +procedure TTestGenerics.TestGen_Except; +begin + StartProgram(false); + Add([ + 'type', + ' TObject = class end;', + ' generic TBird<T> = class', + ' Field: T;', + ' procedure Fly;', + ' end;', + ' Exception = class', + ' end;', + ' generic EBird<T> = class(Exception)', + ' Id: T;', + ' end;', + 'var', + ' b: specialize TBird<word>;', + 'procedure TBird.Fly;', + 'begin', + ' try', + ' except', + ' on E: Exception do Fly;', + ' on EBird: specialize EBird<word> do EBird.Id:=3;', + ' else', + ' Fly;', + ' end;', + 'end;', + 'begin', + '']); + ConvertProgram; + CheckSource('TestGen_Except', + LinesToStr([ // statements + 'rtl.createClass(this, "TObject", null, function () {', + ' this.$init = function () {', + ' };', + ' this.$final = function () {', + ' };', + '});', + 'rtl.createClass(this, "Exception", this.TObject, function () {', + '});', + 'rtl.createClass(this, "TBird$G1", this.TObject, function () {', + ' this.$init = function () {', + ' $mod.TObject.$init.call(this);', + ' this.Field = 0;', + ' };', + ' this.Fly = function () {', + ' try {} catch ($e) {', + ' if ($mod.Exception.isPrototypeOf($e)) {', + ' var E = $e;', + ' this.Fly();', + ' } else if ($mod.EBird$G1.isPrototypeOf($e)) {', + ' var EBird = $e;', + ' EBird.Id = 3;', + ' } else {', + ' this.Fly();', + ' }', + ' };', + ' };', + '}, "TBird<System.Word>");', + 'this.b = null;', + 'rtl.createClass(this, "EBird$G1", this.Exception, function () {', + ' this.$init = function () {', + ' $mod.Exception.$init.call(this);', + ' this.Id = 0;', + ' };', + '}, "EBird<System.Word>");', + '']), + LinesToStr([ // $mod.$main + ''])); +end; + procedure TTestGenerics.TestGen_HelperForArray; begin StartProgram(false); -- cgit v1.2.1 From e02562634b4376b387998d873d2dbcfc0da593fc Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 11:49:01 +0000 Subject: fcl-passrc: started example issue 38784 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49254 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-passrc/tests/tcresolvegenerics.pas | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/fcl-passrc/tests/tcresolvegenerics.pas b/packages/fcl-passrc/tests/tcresolvegenerics.pas index 8c39552070..bf0e95dc5e 100644 --- a/packages/fcl-passrc/tests/tcresolvegenerics.pas +++ b/packages/fcl-passrc/tests/tcresolvegenerics.pas @@ -157,7 +157,7 @@ type procedure TestGenProc_TypeParamCntOverloadNoParams; procedure TestGenProc_TypeParamWithDefaultParamDelphiFail; procedure TestGenProc_ParamSpecWithT; - // ToDo: TestGenProc_ParamSpecWithTNestedType function Fly<T>(a: TBird<T>.TEvent; aSender: T): Word; + procedure TestGenProc_ParamSpecWithTNestedType; // ToDo // ToDo: NestedResultAssign // generic function infer types @@ -2555,6 +2555,34 @@ begin ParseProgram; end; +procedure TTestResolveGenerics.TestGenProc_ParamSpecWithTNestedType; +begin + exit; + + StartProgram(false); + Add([ + '{$mode delphi}', + 'type', + ' TObject = class end;', + ' TBird<T> = class', + ' type', + ' TEvent = procedure(aSender: T);', + ' end;', + 'procedure Fly<T>(Event: TBird<T>.TEvent; Sender: T);', + 'begin', + ' Event(Sender);', + 'end;', + 'procedure Run(aSender: TObject);', + 'begin', + 'end;', + 'var', + ' Bird: TBird<TObject>;', + 'begin', + ' Fly<TObject>(Run,Bird);', + '']); + ParseProgram; +end; + procedure TTestResolveGenerics.TestGenProc_Infer_NeedExplicitFail; begin StartProgram(false); -- cgit v1.2.1 From 1c1eaf2aa2edfc36da8bdc4587beecfd948e1905 Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 12:04:37 +0000 Subject: pastojs: rtti of async function: pfAsync git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49255 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/pastojs/src/fppas2js.pp | 7 ++++++- packages/pastojs/tests/tcmodules.pas | 27 ++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 2054885b0d..0a6deca3df 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -2314,6 +2314,7 @@ type pfVarargs = 2; pfExternal = 4; pfSafeCall = 8; + pfAsync = $10; // PropertyFlag pfGetFunction = 1; // getter is a function pfSetProcedure = 2; // setter is a function @@ -16565,10 +16566,12 @@ begin if ResultTypeInfo<>nil then InnerCall.AddArg(ResultTypeInfo); end; - // add param flags + // add procedure flags Flags:=0; if ptmVarargs in El.Modifiers then inc(Flags,pfVarargs); + if ptmAsync in El.Modifiers then + inc(Flags,pfAsync); if El.CallingConvention=ccSafeCall then inc(Flags,pfSafeCall); if Flags>0 then @@ -20237,6 +20240,8 @@ begin inc(Flags,pfStatic); if ptmVarargs in Proc.ProcType.Modifiers then inc(Flags,pfVarargs); + if ptmAsync in Proc.ProcType.Modifiers then + inc(Flags,pfAsync); if Proc.IsExternal then inc(Flags,pfExternal); if Flags>0 then diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas index d3f5908660..faadb69ff5 100644 --- a/packages/pastojs/tests/tcmodules.pas +++ b/packages/pastojs/tests/tcmodules.pas @@ -29738,17 +29738,19 @@ procedure TTestModule.TestRTTI_Class_Method; begin WithTypeInfo:=true; StartProgram(false); - Add('type'); - Add(' TObject = class'); - Add(' private'); - Add(' procedure Internal; external name ''$intern'';'); - Add(' published'); - Add(' procedure Click; virtual; abstract;'); - Add(' procedure Notify(Sender: TObject); virtual; abstract;'); - Add(' function GetNotify: boolean; external name ''GetNotify'';'); - Add(' procedure Println(a,b: longint); varargs; virtual; abstract;'); - Add(' end;'); - Add('begin'); + Add([ + 'type', + ' TObject = class', + ' private', + ' procedure Internal; external name ''$intern'';', + ' published', + ' procedure Click; virtual; abstract;', + ' procedure Notify(Sender: TObject); virtual; abstract;', + ' function GetNotify: boolean; external name ''GetNotify'';', + ' procedure Println(a,b: longint); varargs; virtual; abstract;', + ' function Fetch(URL: string): word; async; external name ''Fetch'';', + ' end;', + 'begin']); ConvertProgram; CheckSource('TestRTTI_Class_Method', LinesToStr([ // statements @@ -29764,6 +29766,9 @@ begin ' $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, {', ' flags: 2', ' });', + ' $r.addMethod("Fetch", 1, [["URL", rtl.string]], rtl.word, {', + ' flags: 20', + ' });', '});', '']), LinesToStr([ // $mod.$main -- cgit v1.2.1 From ec2bca61ec83873beb28eb2f0df6bc00da70c0a8 Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 13:53:28 +0000 Subject: fcl-passrc: started specialize type reference a<b>.c git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49256 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-passrc/src/pasresolver.pp | 46 ++++++++++++++++++++++--- packages/fcl-passrc/src/pasuseanalyzer.pas | 1 + packages/fcl-passrc/src/pparser.pp | 7 ++-- packages/fcl-passrc/tests/tcresolvegenerics.pas | 6 ++-- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/packages/fcl-passrc/src/pasresolver.pp b/packages/fcl-passrc/src/pasresolver.pp index ed20471c25..e726e9a5c5 100644 --- a/packages/fcl-passrc/src/pasresolver.pp +++ b/packages/fcl-passrc/src/pasresolver.pp @@ -1690,6 +1690,7 @@ type procedure FinishMethodImplHeader(ImplProc: TPasProcedure); virtual; procedure FinishExceptOnExpr; virtual; procedure FinishExceptOnStatement; virtual; + procedure FinishParserSpecializeType(El: TPasSpecializeType); virtual; procedure FinishWithDo(El: TPasImplWithDo); virtual; procedure FinishForLoopHeader(Loop: TPasImplForLoop); virtual; procedure FinishDeclaration(El: TPasElement); virtual; @@ -2153,6 +2154,7 @@ type function PushHelperDotScope(HiType: TPasType): TPasDotBaseScope; function PushTemplateDotScope(TemplType: TPasGenericTemplateType; ErrorEl: TPasElement): TPasDotBaseScope; function PushDotScope(HiType: TPasType): TPasDotBaseScope; + function PushParserSpecializeType(SpecType: TPasSpecializeType): TPasDotBaseScope; function PushWithExprScope(Expr: TPasExpr): TPasWithExprScope; function StashScopes(NewScopeCnt: integer): integer; // returns old StashDepth function StashSubExprScopes: integer; // returns old StashDepth @@ -5238,6 +5240,9 @@ begin begin // El is the first element found -> raise error // ToDo: use the ( as error position + {$IFDEF VerbosePasResolver} + writeln('TPasResolver.OnFindCallElements El=',GetObjPath(El)); + {$ENDIF} RaiseMsg(20170216151525,nIllegalQualifierAfter,sIllegalQualifierAfter, ['(',El.ElementTypeName],Data^.Params); end; @@ -7606,6 +7611,12 @@ begin PopScope; end; +procedure TPasResolver.FinishParserSpecializeType(El: TPasSpecializeType); +begin + if El=nil then ; + PopScope; +end; + procedure TPasResolver.FinishWithDo(El: TPasImplWithDo); begin PopWithScope(El); @@ -18120,6 +18131,13 @@ begin SpecializeElList(GenEl,SpecEl,GenEl.Params,SpecEl.Params,true {$IFDEF CheckPasTreeRefCount},'TPasSpecializeType.Params'{$ENDIF}); + if GenEl.SubType<>nil then + begin + PushParserSpecializeType(SpecEl); + SpecializeElType(GenEl,SpecEl,GenEl.SubType,SpecEl.SubType); + PopScope; + end; + FinishSpecializeType(SpecEl); {$IFDEF VerbosePasResolver} //writeln('TPasResolver.SpecializeSpecializeType ',GetObjName(SpecEl.DestType),' ',GetObjName(SpecEl.CustomData)); @@ -21807,6 +21825,7 @@ end; procedure TPasResolver.BeginScope(ScopeType: TPasScopeType; El: TPasElement); begin case ScopeType of + stSpecializeType: PushParserSpecializeType(El as TPasSpecializeType); stWithExpr: PushWithExprScope(El as TPasExpr); else RaiseMsg(20181210163324,nNotYetImplemented,sNotYetImplemented+' BeginScope',[IntToStr(ord(ScopeType))],nil); @@ -21824,9 +21843,10 @@ begin stResourceString: FinishResourcestring(El as TPasResString); stProcedure: FinishProcedure(El as TPasProcedure); stProcedureHeader: FinishProcedureType(El as TPasProcedureType); + stSpecializeType: FinishParserSpecializeType(El as TPasSpecializeType); + stWithExpr: FinishWithDo(El as TPasImplWithDo); stExceptOnExpr: FinishExceptOnExpr; stExceptOnStatement: FinishExceptOnStatement; - stWithExpr: FinishWithDo(El as TPasImplWithDo); stForLoopHeader: FinishForLoopHeader(El as TPasImplForLoop); stDeclaration: FinishDeclaration(El); stAncestors: FinishAncestors(El as TPasClassType); @@ -22784,6 +22804,12 @@ begin Result:=PushHelperDotScope(HiType); end; +function TPasResolver.PushParserSpecializeType(SpecType: TPasSpecializeType + ): TPasDotBaseScope; +begin + Result:=PushDotScope(SpecType.DestType); +end; + function TPasResolver.PushWithExprScope(Expr: TPasExpr): TPasWithExprScope; var WithEl: TPasImplWithDo; @@ -27709,7 +27735,9 @@ procedure TPasResolver.ComputeElement(El: TPasElement; out var TypeEl: TPasType; begin - if SpecType.CustomData is TPasSpecializeTypeData then + if SpecType.SubType<>nil then + ComputeElement(SpecType.SubType,ResolvedEl,Flags,StartEl) + else if SpecType.CustomData is TPasSpecializeTypeData then begin TypeEl:=TPasSpecializeTypeData(SpecType.CustomData).SpecializedType; if TypeEl=nil then @@ -28393,6 +28421,7 @@ function TPasResolver.ResolveAliasType(aType: TPasType; SkipTypeAlias: boolean ): TPasType; var C: TClass; + SpecType: TPasSpecializeType; begin while aType<>nil do begin @@ -28406,9 +28435,16 @@ begin aType:=NoNil(TResolvedReference(aType.CustomData).Declaration) as TPasType else if C=TPasSpecializeType then begin - if aType.CustomData is TPasSpecializeTypeData then - exit(TPasSpecializeTypeData(aType.CustomData).SpecializedType); - aType:=TPasSpecializeType(aType).DestType; + SpecType:=TPasSpecializeType(aType); + if SpecType.SubType<>nil then + // e.g. a<b>.c + aType:=SpecType.SubType + else + begin + if SpecType.CustomData is TPasSpecializeTypeData then + exit(TPasSpecializeTypeData(SpecType.CustomData).SpecializedType); + aType:=SpecType.DestType; + end; end else exit(aType); diff --git a/packages/fcl-passrc/src/pasuseanalyzer.pas b/packages/fcl-passrc/src/pasuseanalyzer.pas index 54a45c93ff..2a9ab54a24 100644 --- a/packages/fcl-passrc/src/pasuseanalyzer.pas +++ b/packages/fcl-passrc/src/pasuseanalyzer.pas @@ -2471,6 +2471,7 @@ begin if Param is TPasGenericTemplateType then continue; UseElement(Param,rraRead,false); end; + UseElType(El,El.SubType,Mode); end; procedure TPasAnalyzer.UseVariable(El: TPasVariable; diff --git a/packages/fcl-passrc/src/pparser.pp b/packages/fcl-passrc/src/pparser.pp index b3741ee1ff..f24a2aab6b 100644 --- a/packages/fcl-passrc/src/pparser.pp +++ b/packages/fcl-passrc/src/pparser.pp @@ -157,6 +157,7 @@ type stResourceString, // e.g. TPasResString stProcedure, // also method, procedure, constructor, destructor, ... stProcedureHeader, + stSpecializeType, // calls BeginScope to resolve c in a<b>.c stWithExpr, // calls BeginScope after parsing every WITH-expression stExceptOnExpr, stExceptOnStatement, @@ -1766,6 +1767,8 @@ begin ReadSpecializeArguments(ST,ST.Params); if CurToken<>tkGreaterThan then ParseExcTokenError('[20190801113005]'); + // Important: resolve type reference AFTER args, because arg count is needed + ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count); // Check for cascaded specialize A<B>.C or A<B>.C<D> NextToken; @@ -1774,10 +1777,10 @@ begin else begin NextToken; + Engine.BeginScope(stSpecializeType,ST); ST.SubType:=ParseSimpleType(ST,CurSourcePos,GenName,False); + Engine.FinishScope(stSpecializeType,ST); end; - // Important: resolve type reference AFTER args, because arg count is needed - ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count); Engine.FinishScope(stTypeDef,ST); Result:=ST; diff --git a/packages/fcl-passrc/tests/tcresolvegenerics.pas b/packages/fcl-passrc/tests/tcresolvegenerics.pas index bf0e95dc5e..db692e4358 100644 --- a/packages/fcl-passrc/tests/tcresolvegenerics.pas +++ b/packages/fcl-passrc/tests/tcresolvegenerics.pas @@ -157,7 +157,7 @@ type procedure TestGenProc_TypeParamCntOverloadNoParams; procedure TestGenProc_TypeParamWithDefaultParamDelphiFail; procedure TestGenProc_ParamSpecWithT; - procedure TestGenProc_ParamSpecWithTNestedType; // ToDo + procedure TestGenProc_ParamSpecWithTNestedType; // ToDo: NestedResultAssign // generic function infer types @@ -2557,8 +2557,6 @@ end; procedure TTestResolveGenerics.TestGenProc_ParamSpecWithTNestedType; begin - exit; - StartProgram(false); Add([ '{$mode delphi}', @@ -2578,7 +2576,7 @@ begin 'var', ' Bird: TBird<TObject>;', 'begin', - ' Fly<TObject>(Run,Bird);', + ' Fly<TObject>(@Run,Bird);', '']); ParseProgram; end; -- cgit v1.2.1 From 0b3d548d3cbea0b5145e02fccdb7e4be3da6e2f0 Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 14:06:36 +0000 Subject: * fpsr and fpcr are 64 bit on aarch64 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49257 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/aarch64/mathu.inc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtl/aarch64/mathu.inc b/rtl/aarch64/mathu.inc index f55471e963..5e1235171c 100644 --- a/rtl/aarch64/mathu.inc +++ b/rtl/aarch64/mathu.inc @@ -14,25 +14,25 @@ {$asmmode gas} -function getfpcr: dword; nostackframe; assembler; +function getfpcr: qword; nostackframe; assembler; asm mrs x0,fpcr end; -procedure setfpcr(val: dword); nostackframe; assembler; +procedure setfpcr(val: qword); nostackframe; assembler; asm msr fpcr,x0 end; -function getfpsr: dword; nostackframe; assembler; +function getfpsr: qword; nostackframe; assembler; asm mrs x0,fpsr end; -procedure setfpsr(val: dword); nostackframe; assembler; +procedure setfpsr(val: qword); nostackframe; assembler; asm msr fpsr, x0 end; @@ -75,7 +75,7 @@ const fpu_ufe = 1 shl 11; fpu_ixe = 1 shl 12; fpu_ide = 1 shl 15; - fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide; + fpu_exception_mask = qword(fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide); fpu_exception_mask_to_status_mask_shift = 8; @@ -111,13 +111,13 @@ function GetExceptionMask: TFPUExceptionMask; function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask; var - newfpcr: dword; + newfpcr: qword; begin { clear "exception happened" flags } ClearExceptions(false); softfloat_exception_mask:=mask; - { at least the ThunderX AArch64 support apperently hardware exceptions, + { at least the ThunderX AArch64 support apparently hardware exceptions, so set fpcr correctly, thought it might be WI on most implementations it does not hurt } newfpcr:=fpu_exception_mask; @@ -143,7 +143,7 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask; procedure ClearExceptions(RaisePending: Boolean); var - fpsr: dword; + fpsr: qword; f: TFPUException; begin fpsr:=getfpsr; -- cgit v1.2.1 From bdac2b1796398f2fa19a23d12880929ad820b6e3 Mon Sep 17 00:00:00 2001 From: nickysn <nickysn@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 14:31:56 +0000 Subject: * override the raise node for WebAssembly and copy the generic pass_1 implementation. No functional changes. git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49258 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/wasm32/nwasmflw.pas | 71 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/compiler/wasm32/nwasmflw.pas b/compiler/wasm32/nwasmflw.pas index aa82e0e700..41e66b1ce3 100644 --- a/compiler/wasm32/nwasmflw.pas +++ b/compiler/wasm32/nwasmflw.pas @@ -49,6 +49,13 @@ interface procedure pass_generate_code;override; end; + { twasmraisenode } + + twasmraisenode = class(tcgraisenode) + public + function pass_1 : tnode;override; + end; + { twasmtryexceptnode } twasmtryexceptnode = class(tcgtryexceptnode) @@ -68,9 +75,9 @@ implementation uses verbose,globals,systems,globtype,constexp, symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,defcmp, - procinfo,cgbase,pass_1,pass_2,parabase, + procinfo,cgbase,pass_1,pass_2,parabase,compinnr, cpubase,cpuinfo, - nbas,nld,ncon,ncnv, + nbas,nld,ncon,ncnv,ncal,ninl,nmem,nadd, tgobj,paramgr, cgutils,hlcgobj,hlcgcpu; @@ -203,6 +210,65 @@ implementation flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]); end; +{***************************************************************************** + twasmraisenode +*****************************************************************************} + + function twasmraisenode.pass_1 : tnode; + var + statements : tstatementnode; + current_addr : tlabelnode; + raisenode : tcallnode; + begin + result:=internalstatements(statements); + + if assigned(left) then + begin + { first para must be a class } + firstpass(left); + { insert needed typeconvs for addr,frame } + if assigned(right) then + begin + { addr } + firstpass(right); + { frame } + if assigned(third) then + firstpass(third) + else + third:=cpointerconstnode.Create(0,voidpointertype); + end + else + begin + third:=cinlinenode.create(in_get_frame,false,nil); + current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr')); + addstatement(statements,current_addr); + right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner)); + + { raise address off by one so we are for sure inside the action area for the raise } + if tf_use_psabieh in target_info.flags then + right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false)); + end; + + raisenode:=ccallnode.createintern('fpc_raiseexception', + ccallparanode.create(third, + ccallparanode.create(right, + ccallparanode.create(left,nil))) + ); + include(raisenode.callnodeflags,cnf_call_never_returns); + addstatement(statements,raisenode); + end + else + begin + addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil)); + raisenode:=ccallnode.createintern('fpc_reraise',nil); + include(raisenode.callnodeflags,cnf_call_never_returns); + addstatement(statements,raisenode); + end; + left:=nil; + right:=nil; + third:=nil; + end; + {***************************************************************************** twasmtryexceptnode *****************************************************************************} @@ -258,6 +324,7 @@ implementation initialization cifnode:=twasmifnode; cwhilerepeatnode:=twasmwhilerepeatnode; + craisenode:=twasmraisenode; ctryexceptnode:=twasmtryexceptnode; ctryfinallynode:=twasmtryfinallynode; end. -- cgit v1.2.1 From 15b5f77fe00f94a1215a4b2891644df339178b5f Mon Sep 17 00:00:00 2001 From: nickysn <nickysn@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sat, 24 Apr 2021 14:40:07 +0000 Subject: * workaround for the raise node generating invalid WebAssembly code for obtaining the current address. Note that exception handling in WebAssembly doesn't work. This only fixes the raise node enough to generate valid (but not correct) WebAssembly code. This is a temporary fix to allow the SysUtils unit to be compiled. Eventually, exception handling for WebAssembly will need to be rewritten entirely, in order to make exceptions work properly. git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49259 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/wasm32/nwasmflw.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/wasm32/nwasmflw.pas b/compiler/wasm32/nwasmflw.pas index 41e66b1ce3..84a230dc1b 100644 --- a/compiler/wasm32/nwasmflw.pas +++ b/compiler/wasm32/nwasmflw.pas @@ -217,7 +217,7 @@ implementation function twasmraisenode.pass_1 : tnode; var statements : tstatementnode; - current_addr : tlabelnode; + //current_addr : tlabelnode; raisenode : tcallnode; begin result:=internalstatements(statements); @@ -240,9 +240,10 @@ implementation else begin third:=cinlinenode.create(in_get_frame,false,nil); - current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr')); - addstatement(statements,current_addr); - right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner)); + //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr')); + //addstatement(statements,current_addr); + //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner)); + right:=cnilnode.create; { raise address off by one so we are for sure inside the action area for the raise } if tf_use_psabieh in target_info.flags then -- cgit v1.2.1 From 3595ed4d1c56d42ef6f335152ffadb8e11cb20fe Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 08:53:12 +0000 Subject: + Aarch64: use frintz for int(...) instead of creating a helper call git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49260 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aarch64/ncpuinl.pas | 24 +++++++++++++++++++++++- rtl/aarch64/math.inc | 30 +++++++++++++++--------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/compiler/aarch64/ncpuinl.pas b/compiler/aarch64/ncpuinl.pas index a2e5f1352f..26fd698dae 100644 --- a/compiler/aarch64/ncpuinl.pas +++ b/compiler/aarch64/ncpuinl.pas @@ -1,7 +1,7 @@ { Copyright (c) 1998-2002 by Florian Klaempfl - Generates ARM inline nodes + Generates AAarch64 inline nodes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ interface function first_sqrt_real: tnode; override; function first_round_real: tnode; override; function first_trunc_real: tnode; override; + function first_int_real: tnode; override; function first_fma : tnode; override; procedure second_abs_real; override; procedure second_sqr_real; override; @@ -42,6 +43,7 @@ interface procedure second_abs_long; override; procedure second_round_real; override; procedure second_trunc_real; override; + procedure second_int_real; override; procedure second_get_frame; override; procedure second_fma; override; procedure second_prefetch; override; @@ -108,6 +110,13 @@ implementation end; + function taarch64inlinenode.first_int_real : tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + function taarch64inlinenode.first_fma : tnode; begin if ((is_double(resultdef)) or (is_single(resultdef))) then @@ -187,6 +196,19 @@ implementation end; + procedure taarch64inlinenode.second_int_real; + var + hreg: tregister; + begin + secondpass(left); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef)); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTZ,location.register,left.location.register)); + cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList); + end; + + procedure taarch64inlinenode.second_get_frame; begin location_reset(location,LOC_CREGISTER,OS_ADDR); diff --git a/rtl/aarch64/math.inc b/rtl/aarch64/math.inc index 8be40b21a8..de98808322 100644 --- a/rtl/aarch64/math.inc +++ b/rtl/aarch64/math.inc @@ -53,33 +53,33 @@ {$ifndef FPC_SYSTEM_HAS_INT} {$define FPC_SYSTEM_HAS_INT} - function fpc_int_real(d : ValReal) : ValReal;assembler;nostackframe;compilerproc; - asm - // { round as floating point towards zero } - frintz d0,d0 + function fpc_int_real(d : ValReal) : ValReal;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; end; {$endif FPC_SYSTEM_HAS_INT} {$ifndef FPC_SYSTEM_HAS_TRUNC} {$define FPC_SYSTEM_HAS_TRUNC} - function fpc_trunc_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; - asm - // { round to signed integer towards zero } - fcvtzs x0,d0 + function fpc_trunc_real(d : ValReal) : int64;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; end; {$endif FPC_SYSTEM_HAS_TRUNC} {$ifndef FPC_SYSTEM_HAS_ROUND} {$define FPC_SYSTEM_HAS_ROUND} - function fpc_round_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; - asm - // { round as floating point using current rounding mode } - frintx d0,d0 - // { convert to signed integer rounding towards zero (there's no "round to - // integer using current rounding mode") } - fcvtzs x0,d0 + function fpc_round_real(d : ValReal) : int64;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; end; {$endif FPC_SYSTEM_HAS_ROUND} -- cgit v1.2.1 From ad68af41e644837d3e0bb7b1934f4eaa336d5af4 Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 09:26:47 +0000 Subject: + Aarch64: directly inline code for frac(...) git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49261 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aarch64/ncpuinl.pas | 48 +++++++++++++++++++++++++++++++++----------- rtl/aarch64/math.inc | 11 ++++++++++ 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/compiler/aarch64/ncpuinl.pas b/compiler/aarch64/ncpuinl.pas index 26fd698dae..1ea4537b3b 100644 --- a/compiler/aarch64/ncpuinl.pas +++ b/compiler/aarch64/ncpuinl.pas @@ -36,6 +36,7 @@ interface function first_round_real: tnode; override; function first_trunc_real: tnode; override; function first_int_real: tnode; override; + function first_frac_real: tnode; override; function first_fma : tnode; override; procedure second_abs_real; override; procedure second_sqr_real; override; @@ -44,6 +45,7 @@ interface procedure second_round_real; override; procedure second_trunc_real; override; procedure second_int_real; override; + procedure second_frac_real; override; procedure second_get_frame; override; procedure second_fma; override; procedure second_prefetch; override; @@ -112,21 +114,29 @@ implementation function taarch64inlinenode.first_int_real : tnode; begin - expectloc:=LOC_MMREGISTER; - result:=nil; + expectloc:=LOC_MMREGISTER; + result:=nil; end; - function taarch64inlinenode.first_fma : tnode; - begin - if ((is_double(resultdef)) or (is_single(resultdef))) then - begin - expectloc:=LOC_MMREGISTER; - Result:=nil; - end - else - Result:=inherited first_fma; - end; + function taarch64inlinenode.first_frac_real : tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + function taarch64inlinenode.first_fma : tnode; + begin + if ((is_double(resultdef)) or (is_single(resultdef))) then + begin + expectloc:=LOC_MMREGISTER; + Result:=nil; + end + else + Result:=inherited first_fma; + end; + procedure taarch64inlinenode.second_abs_real; begin @@ -209,6 +219,20 @@ implementation end; + procedure taarch64inlinenode.second_frac_real; + var + hreg: tregister; + begin + secondpass(left); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef)); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTZ,location.register,left.location.register)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_FSUB,location.register,left.location.register,location.register)); + cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList); + end; + + procedure taarch64inlinenode.second_get_frame; begin location_reset(location,LOC_CREGISTER,OS_ADDR); diff --git a/rtl/aarch64/math.inc b/rtl/aarch64/math.inc index de98808322..a526128870 100644 --- a/rtl/aarch64/math.inc +++ b/rtl/aarch64/math.inc @@ -72,6 +72,17 @@ end; {$endif FPC_SYSTEM_HAS_TRUNC} +{$ifndef VER3_2} + {$ifndef FPC_SYSTEM_HAS_FRAC} + {$define FPC_SYSTEM_HAS_FRAC} + function fpc_frac_real(d : ValReal) : ValReal;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; + end; + {$endif FPC_SYSTEM_HAS_FRAC} +{$endif VER3_2} {$ifndef FPC_SYSTEM_HAS_ROUND} {$define FPC_SYSTEM_HAS_ROUND} -- cgit v1.2.1 From bf1c5ea44c8098917fda86c5ecd18befd9e40844 Mon Sep 17 00:00:00 2001 From: nickysn <nickysn@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 15:58:59 +0000 Subject: * prevention of dangling pointers and use after free after free_unregistered_localsymtable_elements git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49262 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/pmodules.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/pmodules.pas b/compiler/pmodules.pas index d5037f7d60..9094500eb5 100644 --- a/compiler/pmodules.pas +++ b/compiler/pmodules.pas @@ -614,6 +614,7 @@ implementation i: longint; def: tdef; sym: tsym; + tmpidx: Integer; begin for i:=current_module.localsymtable.deflist.count-1 downto 0 do begin @@ -633,6 +634,10 @@ implementation tprocdef(def).procsym.is_registered then tprocsym(tprocdef(def).procsym).ProcdefList.Remove(def); current_module.localsymtable.deletedef(def); + { this prevents a dangling pointer and use after free } + tmpidx:=current_module.deflist.IndexOfItem(def,FromEnd); + if tmpidx<>-1 then + current_module.deflist[tmpidx]:=nil; end; end; { from high to low so we hopefully have moves of less data } -- cgit v1.2.1 From 659d1f1896ac8aced4977dcc51be38006a7e10d4 Mon Sep 17 00:00:00 2001 From: nickysn <nickysn@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 16:09:24 +0000 Subject: * makefile regenerated with latest fpcmake git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49263 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-mustache/Makefile | 49 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/fcl-mustache/Makefile b/packages/fcl-mustache/Makefile index 32529caba3..f0784c60a9 100644 --- a/packages/fcl-mustache/Makefile +++ b/packages/fcl-mustache/Makefile @@ -2,7 +2,7 @@ # Don't edit, this file is generated by FPCMake Version 2.0.0 # default: all -MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc +MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-freebsd aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc BSDs = freebsd netbsd openbsd darwin dragonfly UNIXs = linux $(BSDs) solaris qnx haiku aix LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari @@ -631,10 +631,18 @@ else ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),) FPCMAKE_CROSSGCCOPT=-mabi=32 else +ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv64),) +FPCMAKE_CROSSGCCOPT=-mabi=lp64 +else +ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv32),) +FPCMAKE_CROSSGCCOPT=-mabi=ilp32 +else FPCMAKE_CROSSGCCOPT=-m32 endif endif endif +endif +endif FPCMAKEGCCLIBDIR:=$(shell dirname `gcc $(FPCMAKE_CROSSGCCOPT) -print-libgcc-file-name`) endif endif @@ -2093,6 +2101,17 @@ REQUIRE_PACKAGES_FCL-BASE=1 REQUIRE_PACKAGES_FCL-DB=1 REQUIRE_PACKAGES_FCL-JSON=1 endif +ifeq ($(FULL_TARGET),aarch64-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif ifeq ($(FULL_TARGET),aarch64-darwin) REQUIRE_PACKAGES_RTL=1 REQUIRE_PACKAGES_PASZLIB=1 @@ -2137,7 +2156,18 @@ REQUIRE_PACKAGES_FCL-BASE=1 REQUIRE_PACKAGES_FCL-DB=1 REQUIRE_PACKAGES_FCL-JSON=1 endif -ifeq ($(FULL_TARGET),wasm-wasm) +ifeq ($(FULL_TARGET),wasm32-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +REQUIRE_PACKAGES_FCL-BASE=1 +REQUIRE_PACKAGES_FCL-DB=1 +REQUIRE_PACKAGES_FCL-JSON=1 +endif +ifeq ($(FULL_TARGET),wasm32-wasi) REQUIRE_PACKAGES_RTL=1 REQUIRE_PACKAGES_PASZLIB=1 REQUIRE_PACKAGES_FCL-PROCESS=1 @@ -2725,11 +2755,24 @@ override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR) override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX) endif endif +ifdef SYSROOTPATH +override FPCOPT+=-XR$(SYSROOTPATH) +else +ifeq ($(OS_TARGET),$(OS_SOURCE)) +ifneq ($(findstring $(OS_TARGET),darwin),) +ifneq ($(findstring $(CPU_TARGET),aarch64),) +ifneq ($(wildcard /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk),) +override FPCOPT+=-XR/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk +endif +endif +endif +endif +endif ifdef CREATESHARED override FPCOPT+=-Cg endif ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),) -ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),) +ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),) override FPCOPT+=-Cg endif endif -- cgit v1.2.1 From 39aa8a14702f49b1d129b181c411823cf82177f2 Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 19:24:18 +0000 Subject: * fix bootstrapping on aarch64-linux with 3.2.x git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49264 3ad0048d-3df7-0310-abae-a5850022a9f2 --- rtl/aarch64/math.inc | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/rtl/aarch64/math.inc b/rtl/aarch64/math.inc index a526128870..6bdaebbcff 100644 --- a/rtl/aarch64/math.inc +++ b/rtl/aarch64/math.inc @@ -51,47 +51,47 @@ {$endif FPC_SYSTEM_HAS_SQRT} - {$ifndef FPC_SYSTEM_HAS_INT} - {$define FPC_SYSTEM_HAS_INT} - function fpc_int_real(d : ValReal) : ValReal;compilerproc; +{$ifndef VER3_2} + {$ifndef FPC_SYSTEM_HAS_FRAC} + {$define FPC_SYSTEM_HAS_FRAC} + function fpc_frac_real(d : ValReal) : ValReal;compilerproc; begin { Function is handled internal in the compiler } runerror(207); result:=0; end; + {$endif FPC_SYSTEM_HAS_FRAC} +{$endif VER3_2} + + + {$ifndef FPC_SYSTEM_HAS_INT} + {$define FPC_SYSTEM_HAS_INT} + function fpc_int_real(d : ValReal) : ValReal;assembler;nostackframe;compilerproc; + asm + // { round as floating point towards zero } + frintz d0,d0 + end; {$endif FPC_SYSTEM_HAS_INT} {$ifndef FPC_SYSTEM_HAS_TRUNC} {$define FPC_SYSTEM_HAS_TRUNC} - function fpc_trunc_real(d : ValReal) : int64;compilerproc; - begin - { Function is handled internal in the compiler } - runerror(207); - result:=0; + function fpc_trunc_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; + asm + // { round to signed integer towards zero } + fcvtzs x0,d0 end; {$endif FPC_SYSTEM_HAS_TRUNC} -{$ifndef VER3_2} - {$ifndef FPC_SYSTEM_HAS_FRAC} - {$define FPC_SYSTEM_HAS_FRAC} - function fpc_frac_real(d : ValReal) : ValReal;compilerproc; - begin - { Function is handled internal in the compiler } - runerror(207); - result:=0; - end; - {$endif FPC_SYSTEM_HAS_FRAC} -{$endif VER3_2} {$ifndef FPC_SYSTEM_HAS_ROUND} {$define FPC_SYSTEM_HAS_ROUND} - function fpc_round_real(d : ValReal) : int64;compilerproc; - begin - { Function is handled internal in the compiler } - runerror(207); - result:=0; + function fpc_round_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; + asm + // { round as floating point using current rounding mode } + frintx d0,d0 + // { convert to signed integer rounding towards zero (there's no "round to + // integer using current rounding mode") } + fcvtzs x0,d0 end; {$endif FPC_SYSTEM_HAS_ROUND} - - -- cgit v1.2.1 From 8d4e1bf0c2fd6635c735b42aebc3fe0645f270bf Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Sun, 25 Apr 2021 19:49:26 +0000 Subject: * decrease macro nesting counter early when expanding empty macro to avoid errors about too depth macro nesting, resolves #38802 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49265 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/scanner.pas | 19 ++++++++++++++----- tests/webtbs/tw38802.pp | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 tests/webtbs/tw38802.pp diff --git a/compiler/scanner.pas b/compiler/scanner.pas index b33f7a73c5..9632471f24 100644 --- a/compiler/scanner.pas +++ b/compiler/scanner.pas @@ -4883,12 +4883,21 @@ type inc(yylexcount); substitutemacro(pattern,mac.buftext,mac.buflen, mac.fileinfo.line,mac.fileinfo.fileindex); - { handle empty macros } + { handle empty macros } if c=#0 then - reload; - readtoken(false); - { that's all folks } - dec(yylexcount); + begin + reload; + { avoid macro nesting error in case of + a sequence of empty macros, see #38802 } + dec(yylexcount); + readtoken(false); + end + else + begin + readtoken(false); + { that's all folks } + dec(yylexcount); + end; exit; end else diff --git a/tests/webtbs/tw38802.pp b/tests/webtbs/tw38802.pp new file mode 100644 index 0000000000..87237eb77b --- /dev/null +++ b/tests/webtbs/tw38802.pp @@ -0,0 +1,24 @@ +{$mode objfpc} {$h+} {$macro on} + +begin + // Warning: Expanding of macros exceeds a depth of 16. + // If macros contain any source code (barring comments and directives) — even 'begin end;', this will compile. + {$define do_A :=} + {$define do_B :=} + {$define do_C :=} + {$define do_D :=} + {$define do_E :=} + {$define do_F :=} + {$define do_G :=} + {$define do_H :=} + {$define do_I :=} + {$define do_J :=} + {$define do_K :=} + {$define do_L :=} + {$define do_M :=} + {$define do_N :=} + {$define do_O :=} + {$define do_P :=} + {$define do_Q :=} + do_A do_B do_C do_D do_E do_F do_G do_H do_I do_J do_K do_L do_M do_N do_O do_P do_Q +end. -- cgit v1.2.1 From 25893d4612247064685c7f615f30ac14a88ab9b8 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 20:43:07 +0000 Subject: * Use FGeneralCriticalSection for LogIndent and LogUnindent. Add FIndentCount integer field. Add FWorkerPrefix string field. Use try/finally block to keep track of LogLevel git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49266 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fpmkunit/src/fpmkunit.pp | 115 ++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/packages/fpmkunit/src/fpmkunit.pp b/packages/fpmkunit/src/fpmkunit.pp index 70b51d34e9..41e9852060 100644 --- a/packages/fpmkunit/src/fpmkunit.pp +++ b/packages/fpmkunit/src/fpmkunit.pp @@ -1230,6 +1230,7 @@ Type FInteractive : boolean; FProgressMax : integer; FProgressCount : integer; + FIndentCount : integer; FExternalPackages : TPackages; // Events FOnLog: TLogEvent; @@ -1238,7 +1239,9 @@ Type FOnFinishCopy: TNotifyEvent; FCachedlibcPath: string; +{$ifndef NO_THREADING} FGeneralCriticalSection: TRTLCriticalSection; +{$endif NO_THREADING} {$ifdef HAS_UNIT_ZIPPER} FZipper: TZipper; FGZFileStream: TGZFileStream; @@ -1452,6 +1455,7 @@ Type FCompilationOK: boolean; FDone: boolean; FErrorMessage: string; + FWorkerPrefix: string; FNotifyMainThreadEvent: PRTLEvent; FNotifyStartTask: PRTLEvent; FPackage: TPackage; @@ -3407,17 +3411,17 @@ begin begin { synchronise with ReadWriteBarrier in mainthread for same reason as above } ReadWriteBarrier; - FBuildEngine.log(vlInfo,'Compiling: '+APackage.Name); + FBuildEngine.log(vlInfo,FWorkerPrefix+'Compiling: '+APackage.Name); FCompilationOK:=false; try FBuildEngine.Compile(APackage); FCompilationOK:=true; - FBuildEngine.log(vlInfo,'Done compiling: '+APackage.Name); + FBuildEngine.log(vlInfo,FWorkerPrefix+'Done compiling: '+APackage.Name); RaiseMainEvent; except on E: Exception do begin - FErrorMessage := 'Failed compiling: '+APackage.Name+': '+E.Message; + FErrorMessage := FWorkerPrefix+'Failed compiling: '+APackage.Name+': '+E.Message; FBuildEngine.log(vlInfo,FErrorMessage); RaiseMainEvent; end; @@ -6007,6 +6011,7 @@ begin // With --start-dir=/path/to/sources. FStartDir:=includeTrailingPathDelimiter(GetCurrentDir); FExternalPackages:=TPackages.Create(TPackage); + FIndentCount:=0; FNotifyEventCollection := TNotifyEventCollection.create([neaAfterCompile, neaBeforeCompile, neaAfterInstall, neaBeforeInstall, neaAfterClean, neaBeforeClean, neaAfterArchive, neaBeforeArchive, neaAfterManifest, neaBeforeManifest, neaAfterPkgList, neaBeforePkgList, @@ -6021,6 +6026,8 @@ destructor TBuildEngine.Destroy; begin FreeAndNil(FExternalPackages); FreeAndNil(FNotifyEventCollection); + If FIndentCount<>0 then + Log(vlDebug,Format('Log level at exit is %d',[FIndentCount])); {$ifndef NO_THREADING} DoneCriticalsection(FGeneralCriticalSection); @@ -6419,13 +6426,33 @@ end; procedure TBuildEngine.LogIndent; begin - GLogPrefix:=GLogPrefix+' '; +{$ifndef NO_THREADING} + EnterCriticalSection(FGeneralCriticalSection); +{$endif NO_THREADING} + Inc(FIndentCount); + if not (vlDebug in Installer.FLogLevels) then + GLogPrefix:=GLogPrefix+' ' + else + GLogPrefix:=IntToStr(FIndentCount)+'> '; +{$ifndef NO_THREADING} + LeaveCriticalSection(FGeneralCriticalSection); +{$endif NO_THREADING} end; procedure TBuildEngine.LogUnIndent; begin - Delete(GLogPrefix,1,2); +{$ifndef NO_THREADING} + EnterCriticalSection(FGeneralCriticalSection); +{$endif NO_THREADING} + Dec(FIndentCount); + if not (vlDebug in Installer.FLogLevels) then + Delete(GLogPrefix,1,2) + else + GLogPrefix:=IntToStr(FIndentCount)+'> '; +{$ifndef NO_THREADING} + LeaveCriticalSection(FGeneralCriticalSection); +{$endif NO_THREADING} end; @@ -6433,10 +6460,19 @@ procedure TBuildEngine.Log(Level: TVerboseLevel; Msg: String); begin If Assigned(FOnLog) then begin +{$ifndef NO_THREADING} + EnterCriticalSection(FGeneralCriticalSection); + try +{$endif NO_THREADING} if Level in [vlInfo,vlDebug] then FOnLog(Level,GLogPrefix+Msg) else FOnLog(Level,Msg); +{$ifndef NO_THREADING} + finally + LeaveCriticalSection(FGeneralCriticalSection); + end; +{$endif NO_THREADING} end; end; @@ -6905,32 +6941,34 @@ begin begin // Debug information Log(vlDebug,SDbgResolvingSourcesOfTarget,[T.Name,MakeTargetString(ACPU,AOS)]); - LogIndent; + try + LogIndent; - case T.TargetType of - ttProgram, - ttSharedLibrary, - ttUnit, - ttImplicitUnit : - begin - if T.FTargetSourceFileName<>'' then - Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name]) - else - FindMainSource(T); - if T.Dependencies.Count>0 then - FindIncludeSources(T); - end; - ttExampleUnit, - ttExampleProgram : - begin - if T.FTargetSourceFileName<>'' then - Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name]) - else - FindExampleSource(T); - end; + case T.TargetType of + ttProgram, + ttSharedLibrary, + ttUnit, + ttImplicitUnit : + begin + if T.FTargetSourceFileName<>'' then + Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name]) + else + FindMainSource(T); + if T.Dependencies.Count>0 then + FindIncludeSources(T); + end; + ttExampleUnit, + ttExampleProgram : + begin + if T.FTargetSourceFileName<>'' then + Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name]) + else + FindExampleSource(T); + end; + end; + finally + LogUnIndent; end; - - LogUnIndent; end; end; finally @@ -7484,6 +7522,7 @@ Var Env : TStrings; begin Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]); + try LogIndent; ExecuteCommands(ATarget.Commands,caBeforeCompile); If Assigned(ATarget.BeforeCompile) then @@ -7514,7 +7553,9 @@ begin ATarget.AfterCompile(ATarget); ExecuteCommands(ATarget.Commands,caAfterCompile); end; + finally LogUnIndent; + end; end; @@ -7525,6 +7566,7 @@ Var D : TDependency; begin Log(vlDebug, Format(SDbgCompilingDependenciesOfTarget, [ATarget.Name])); + try LogIndent; For I:=0 to ATarget.Dependencies.Count-1 do begin @@ -7558,7 +7600,9 @@ begin Error(SErrDepUnknownTarget,[D.Value, ATarget.Name, APackage.Name]); end; end; + finally LogUnIndent; + end; end; @@ -7567,6 +7611,7 @@ begin if ATarget.State<>tsNeutral then Error(SErrInvalidState,[ATarget.Name]); Log(vlDebug, Format(SDbgConsideringTarget, [ATarget.Name])); + try LogIndent; ATarget.FTargetState:=tsConsidering; ResolveDependencies(ATarget.Dependencies,ATarget.Collection as TTargets); @@ -7578,7 +7623,9 @@ begin end else ATarget.FTargetState:=tsNoCompile; + finally LogUnIndent; + end; end; @@ -8037,6 +8084,7 @@ begin if APackage.State<>tsNeutral then Error(SErrInvalidState,[APackage.Name]); Log(vlDebug,SDbgConsideringPackage,[APackage.Name]); + try LogIndent; if Defaults.ThreadsAmount=-1 then APackage.FTargetState:=tsConsidering; @@ -8049,6 +8097,7 @@ begin else if CheckDependencies(APackage, true)=cdNotYetAvailable then begin log(vlInfo,'Delaying package '+apackage.name); + //LogUnIndent; Done in Finally below result := False; Exit; end; @@ -8062,7 +8111,9 @@ begin APackage.FTargetState:=tsNoCompile; inc(FProgressCount); end; + finally LogUnIndent; + end; end; @@ -8696,7 +8747,10 @@ begin begin Threads[Thr] := TCompileWorkerThread.Create(self,NotifyThreadWaiting); if assigned(Threads[Thr]) then - inc(ThreadCount); + begin + inc(ThreadCount); + Threads[Thr].FWorkerPrefix:=Format('(%d/%d) ',[Thr,Defaults.ThreadsAmount]); + end; end; except on E: Exception do @@ -8712,6 +8766,7 @@ begin while not Finished do begin RTLeventWaitFor(NotifyThreadWaiting); + RTLeventResetEvent(NotifyThreadWaiting); for Thr:=0 to Defaults.ThreadsAmount-1 do if assigned(Threads[Thr]) and not Finished then ProcessThreadResult(Threads[Thr]); -- cgit v1.2.1 From 777a40cb89ae38ff1e747b4fac54cc736808eaad Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 20:52:02 +0000 Subject: * patch by Christo Crause to fix #38789: writing of linker commands should not depent in -s git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49267 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/systems/t_freertos.pas | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/systems/t_freertos.pas b/compiler/systems/t_freertos.pas index 027d29f15c..2c815cfbed 100644 --- a/compiler/systems/t_freertos.pas +++ b/compiler/systems/t_freertos.pas @@ -955,6 +955,8 @@ var t: Text; hp: TCmdStrListItem; filepath: TCmdStr; + i,j: integer; + lib: AnsiString; {$endif XTENSA} begin {$ifdef XTENSA} @@ -1139,6 +1141,20 @@ begin if ioresult<>0 then exit; + { extract libraries from linker options and add to static libraries list } + Info.ExtraOptions:=trim(Info.ExtraOptions); + i := pos('-l', Info.ExtraOptions); + while i > 0 do + begin + j:=pos(' ',Info.ExtraOptions); + if j=0 then + j:=length(Info.ExtraOptions)+1; + lib:=copy(Info.ExtraOptions,i+2,j-i-2); + AddStaticCLibrary(lib); + delete(Info.ExtraOptions,i,j); + trim(Info.ExtraOptions); + i := pos('-l', Info.ExtraOptions); + end; hp:=TCmdStrListItem(StaticLibFiles.First); while assigned(hp) do begin @@ -1256,8 +1272,7 @@ begin Replace(cmdstr,'$GCSECTIONS',GCSectionsStr); Replace(cmdstr,'$DYNLINK',DynLinkStr); end; - if success and not(cs_link_nolink in current_settings.globalswitches) then - success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false); + success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false); { Remove ReponseFile } if success and not(cs_link_nolink in current_settings.globalswitches) then -- cgit v1.2.1 From 16c5a9ecf1133c5ffa58b09811081028ba302927 Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:02:43 +0000 Subject: pastojs: fixed rtti method flags git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49268 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/pastojs/src/fppas2js.pp | 44 +++++++++++++++++------------ packages/pastojs/tests/tcmodules.pas | 54 +++++++++++++++++------------------- utils/pas2js/dist/rtl.js | 5 ++-- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/packages/pastojs/src/fppas2js.pp b/packages/pastojs/src/fppas2js.pp index 0a6deca3df..26983a2843 100644 --- a/packages/pastojs/src/fppas2js.pp +++ b/packages/pastojs/src/fppas2js.pp @@ -16575,7 +16575,11 @@ begin if El.CallingConvention=ccSafeCall then inc(Flags,pfSafeCall); if Flags>0 then + begin + if not (El is TPasFunctionType) then + InnerCall.AddArg(CreateLiteralNull(El)); InnerCall.AddArg(CreateLiteralNumber(El,Flags)); + end; if El.IsOfObject then begin @@ -19828,9 +19832,8 @@ var begin Result:=nil; if Args.Count=0 then - Result:=CreateLiteralNull(Parent) + Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent)) else - begin try Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent)); for i:=0 to Args.Count-1 do @@ -19840,7 +19843,6 @@ begin if Result=nil then Params.Free; end; - end; end; procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument; @@ -20146,6 +20148,7 @@ var OptionsEl: TJSObjectLiteral; ResultTypeInfo: TJSElement; Call: TJSCallExpression; + Flags: Integer; procedure AddOption(const aName: String; JS: TJSElement); var @@ -20155,8 +20158,6 @@ var if OptionsEl=nil then begin OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc)); - if ResultTypeInfo=nil then - Call.AddArg(CreateLiteralNull(Proc)); Call.AddArg(OptionsEl); end; ObjLit:=OptionsEl.Elements.AddElement; @@ -20167,7 +20168,7 @@ var var FunName: String; C: TClass; - MethodKind, Flags: Integer; + MethodKind: Integer; ResultEl: TPasResultElement; ProcScope, OverriddenProcScope: TPasProcedureScope; OverriddenClass: TPasClassType; @@ -20225,16 +20226,8 @@ begin // param params as [] Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext)); - // param resulttype as typeinfo reference - if C.InheritsFrom(TPasFunction) then - begin - ResultEl:=TPasFunction(Proc).FuncType.ResultEl; - ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl); - if ResultTypeInfo<>nil then - Call.AddArg(ResultTypeInfo); - end; - - // param options if needed as {} + // optional params: + ResultTypeInfo:=nil; Flags:=0; if Proc.IsStatic then inc(Flags,pfStatic); @@ -20244,9 +20237,24 @@ begin inc(Flags,pfAsync); if Proc.IsExternal then inc(Flags,pfExternal); - if Flags>0 then - AddOption(GetBIName(pbivnRTTIProcFlags),CreateLiteralNumber(Proc,Flags)); Attr:=aResolver.GetAttributeCalls(Members,Index); + + // param resulttype as typeinfo reference + if C.InheritsFrom(TPasFunction) then + begin + ResultEl:=TPasFunction(Proc).FuncType.ResultEl; + ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl); + if ResultTypeInfo<>nil then + Call.AddArg(ResultTypeInfo); + end; + if (ResultTypeInfo=nil) and ((Flags>0) or (length(Attr)>0)) then + Call.AddArg(CreateLiteralNull(Proc)); + + // flags if needed + if (Flags>0) or (length(Attr)>0) then + Call.AddArg(CreateLiteralNumber(Proc,Flags)); + + // param options if needed as {} if length(Attr)>0 then AddOption(GetBIName(pbivnRTTIMemberAttributes), CreateRTTIAttributes(Attr,Proc,AContext)); diff --git a/packages/pastojs/tests/tcmodules.pas b/packages/pastojs/tests/tcmodules.pas index faadb69ff5..26afc5744c 100644 --- a/packages/pastojs/tests/tcmodules.pas +++ b/packages/pastojs/tests/tcmodules.pas @@ -29256,20 +29256,20 @@ begin CheckSource('TestRTTI_ProcType', LinesToStr([ // statements 'this.$rtti.$ProcVar("TProcA", {', - ' procsig: rtl.newTIProcSig(null)', + ' procsig: rtl.newTIProcSig([])', '});', 'this.$rtti.$MethodVar("TMethodB", {', - ' procsig: rtl.newTIProcSig(null),', + ' procsig: rtl.newTIProcSig([]),', ' methodkind: 0', '});', 'this.$rtti.$ProcVar("TProcC", {', - ' procsig: rtl.newTIProcSig(null, 2)', + ' procsig: rtl.newTIProcSig([], null, 2)', '});', 'this.$rtti.$ProcVar("TProcD", {', ' procsig: rtl.newTIProcSig([["i", rtl.longint], ["j", rtl.string, 2], ["c", rtl.char, 1], ["d", rtl.double, 4]])', '});', 'this.$rtti.$ProcVar("TProcE", {', - ' procsig: rtl.newTIProcSig(null, rtl.nativeint)', + ' procsig: rtl.newTIProcSig([], rtl.nativeint)', '});', 'this.$rtti.$ProcVar("TProcF", {', ' procsig: rtl.newTIProcSig([["p", this.$rtti["TProcA"], 2]], rtl.nativeuint)', @@ -29578,13 +29578,13 @@ begin ' this.Fly = function () {', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("Fly", 0, null);', + ' $r.addMethod("Fly", 0, []);', '});', 'rtl.createClass(this, "TEagle", this.TBird, function () {', ' this.Fly = function () {', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("Fly", 0, null);', + ' $r.addMethod("Fly", 0, []);', '});', '']), LinesToStr([ // $mod.$main @@ -29760,15 +29760,11 @@ begin ' this.$final = function () {', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("Click", 0, null);', + ' $r.addMethod("Click", 0, []);', ' $r.addMethod("Notify", 0, [["Sender", $r]]);', - ' $r.addMethod("GetNotify", 1, null, rtl.boolean,{flags: 4});', - ' $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, {', - ' flags: 2', - ' });', - ' $r.addMethod("Fetch", 1, [["URL", rtl.string]], rtl.word, {', - ' flags: 20', - ' });', + ' $r.addMethod("GetNotify", 1, [], rtl.boolean, 4);', + ' $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, 2);', + ' $r.addMethod("Fetch", 1, [["URL", rtl.string]], rtl.word, 20);', '});', '']), LinesToStr([ // $mod.$main @@ -30512,7 +30508,7 @@ begin ' this.$final = function () {', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("DoIt", 0, null);', + ' $r.addMethod("DoIt", 0, []);', '});', 'rtl.createClass(this, "TSky", this.TObject, function () {', ' this.DoIt = function () {', @@ -30554,14 +30550,14 @@ begin ' this.DoIt = function () {', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("DoIt", 0, null);', + ' $r.addMethod("DoIt", 0, []);', '});', 'rtl.createClass(this, "TSky", this.TObject, function () {', ' this.DoIt = function () {', ' $mod.TObject.DoIt.call(this);', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("DoIt", 0, null);', + ' $r.addMethod("DoIt", 0, []);', '});', '']), LinesToStr([ // $mod.$main @@ -30638,7 +30634,7 @@ begin '});', 'this.$rtti.$Class("TBridge");', 'this.$rtti.$ProcVar("TProc", {', - ' procsig: rtl.newTIProcSig(null, this.$rtti["TBridge"])', + ' procsig: rtl.newTIProcSig([], this.$rtti["TBridge"])', '});', 'rtl.createClass(this, "TOger", this.TObject, function () {', ' this.$init = function () {', @@ -30701,7 +30697,7 @@ begin ' instancetype: this.$rtti["TObject"]', '});', 'this.$rtti.$ProcVar("TProcA", {', - ' procsig: rtl.newTIProcSig(null, this.$rtti["TClass"])', + ' procsig: rtl.newTIProcSig([], this.$rtti["TClass"])', '});', 'rtl.createClass(this, "TObject", null, function () {', ' this.$init = function () {', @@ -31174,10 +31170,10 @@ begin ' eltype: rtl.string', '});', 'this.$rtti.$ProcVar("TProc", {', - ' procsig: rtl.newTIProcSig(null)', + ' procsig: rtl.newTIProcSig([])', '});', 'this.$rtti.$MethodVar("TMethod", {', - ' procsig: rtl.newTIProcSig(null),', + ' procsig: rtl.newTIProcSig([]),', ' methodkind: 0', '});', 'this.StaticArray = rtl.arraySetLength(null,"",2);', @@ -31462,7 +31458,7 @@ begin ' null,', ' function () {', ' var $r = this.$rtti;', - ' $r.addMethod("GetItem", 1, null, rtl.longint);', + ' $r.addMethod("GetItem", 1, [], rtl.longint);', ' $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);', ' $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");', ' }', @@ -31529,8 +31525,8 @@ begin ' this.$kind = "com";', ' var $r = this.$rtti;', ' $r.addMethod("QueryInterface", 1, [["iid", $mod.$rtti["TGuid"], 2], ["obj", null, 4]], rtl.longint);', - ' $r.addMethod("_AddRef", 1, null, rtl.longint);', - ' $r.addMethod("_Release", 1, null, rtl.longint);', + ' $r.addMethod("_AddRef", 1, [], rtl.longint);', + ' $r.addMethod("_Release", 1, [], rtl.longint);', ' }', ');', 'rtl.createInterface(', @@ -31541,7 +31537,7 @@ begin ' this.IUnknown,', ' function () {', ' var $r = this.$rtti;', - ' $r.addMethod("GetItem", 1, null, rtl.longint);', + ' $r.addMethod("GetItem", 1, [], rtl.longint);', ' $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);', ' $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");', ' }', @@ -31593,7 +31589,7 @@ begin ' return Result;', ' };', ' var $r = this.$rtti;', - ' $r.addMethod("GetItem", 1, null, rtl.longint);', + ' $r.addMethod("GetItem", 1, [], rtl.longint);', ' $r.addProperty("Item", 1, rtl.longint, "GetItem", "");', '});', 'this.t = null;', @@ -31681,8 +31677,8 @@ begin ' pas.system.IUnknown,', ' function () {', ' var $r = this.$rtti;', - ' $r.addMethod("Swoop", 1, null, pas.unit2.$rtti["TWordArray"]);', - ' $r.addMethod("Glide", 1, null, pas.unit2.$rtti["TArray<System.Word>"]);', + ' $r.addMethod("Swoop", 1, [], pas.unit2.$rtti["TWordArray"]);', + ' $r.addMethod("Glide", 1, [], pas.unit2.$rtti["TArray<System.Word>"]);', ' }', ');', 'this.Fly = function () {', @@ -31887,7 +31883,7 @@ begin ' attr: [$mod.TCustomAttribute, "Create$1", [14]]', ' }', ' );', - ' $r.addMethod("Fly", 0, null, null, {', + ' $r.addMethod("Fly", 0, [], null, 0, {', ' attr: [$mod.TCustomAttribute, "Create$1", [15]]', ' });', '});', diff --git a/utils/pas2js/dist/rtl.js b/utils/pas2js/dist/rtl.js index 1c5bc6914d..9209239f8c 100644 --- a/utils/pas2js/dist/rtl.js +++ b/utils/pas2js/dist/rtl.js @@ -1354,11 +1354,10 @@ var rtl = { }; }; }; - tis.addMethod = function(name,methodkind,params,result,options){ + tis.addMethod = function(name,methodkind,params,result,flags,options){ var t = this.$addMember(name,rtl.tTypeMemberMethod,options); t.methodkind = methodkind; - t.procsig = rtl.newTIProcSig(params); - t.procsig.resulttype = result?result:null; + t.procsig = rtl.newTIProcSig(params,result?result:null,flags?flags:0); this.methods.push(name); return t; }; -- cgit v1.2.1 From 678772aee893ab08024f2fc893e60bd717ea5833 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:10:25 +0000 Subject: Add -march=XXX option for aarch64 external assemblers git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49269 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aarch64/agcpugas.pas | 44 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/compiler/aarch64/agcpugas.pas b/compiler/aarch64/agcpugas.pas index 2487fa1cb1..8026765fc3 100644 --- a/compiler/aarch64/agcpugas.pas +++ b/compiler/aarch64/agcpugas.pas @@ -41,10 +41,12 @@ unit agcpugas; TAArch64Assembler=class(TGNUassembler) constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override; + function MakeCmdLine: TCmdStr; override; end; TAArch64AppleAssembler=class(TAppleGNUassembler) constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override; + function MakeCmdLine: TCmdStr; override; end; TAArch64ClangGASAssembler=class(TAArch64Assembler) @@ -53,6 +55,7 @@ unit agcpugas; protected function sectionflags(secflags:TSectionFlags):string;override; public + function MakeCmdLine: TCmdStr; override; procedure WriteAsmList; override; end; @@ -64,6 +67,18 @@ unit agcpugas; const cputype_to_gas_march : array[tcputype] of string = ( + '', // cpu_none + '', // armv8 is not accepted by GNU assembler + 'armv8-a', + 'armv8.1-a', + 'armv8.2-a', + 'armv8.3-a', + 'armv8.4-a', + 'armv8.5-a', + 'armv8.6-a' + ); + + cputype_to_clang_march : array[tcputype] of string = ( '', // cpu_none 'armv8', 'armv8-a', @@ -94,6 +109,15 @@ unit agcpugas; InstrWriter := TAArch64InstrWriter.create(self); end; + function TAArch64Assembler.MakeCmdLine: TCmdStr; + begin + result:=inherited MakeCmdLine; + if cputype_to_gas_march[current_settings.cputype] <> '' then + Replace(result,'$MARCHOPT','-march='+cputype_to_gas_march[current_settings.cputype]) + else + Replace(result,'$MARCHOPT',''); + end; + {****************************************************************************} { Apple AArch64 Assembler writer } {****************************************************************************} @@ -105,10 +129,24 @@ unit agcpugas; end; + function TAArch64AppleAssembler.MakeCmdLine: TCmdStr; + begin + result:=inherited MakeCmdLine; + if cputype_to_gas_march[current_settings.cputype] <> '' then + Replace(result,'$MARCHOPT','-march='+cputype_to_gas_march[current_settings.cputype]) + else + Replace(result,'$MARCHOPT',''); + end; + {****************************************************************************} { CLang AArch64 Assembler writer } {****************************************************************************} + function TAArch64ClangGASAssembler.MakeCmdLine: TCmdStr; + begin + result:=inherited MakeCmdLine; + end; + procedure TAArch64ClangGASAssembler.TransformSEHDirectives(list:TAsmList); function convert_unwinddata(list:tasmlist):tdynamicarray; @@ -773,7 +811,7 @@ unit agcpugas; id : as_gas; idtxt : 'AS'; asmbin : 'as'; - asmcmd : '-o $OBJ $EXTRAOPT $ASM'; + asmcmd : '-o $OBJ $MARCHOPT $EXTRAOPT $ASM'; supported_targets : [system_aarch64_freebsd,system_aarch64_linux,system_aarch64_android]; flags : [af_needar,af_smartlink_sections]; labelprefix : '.L'; @@ -787,7 +825,7 @@ unit agcpugas; id : as_clang_asdarwin; idtxt : 'CLANG'; asmbin : 'clang'; - asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM'; + asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM'; supported_targets : [system_aarch64_ios,system_aarch64_darwin]; flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi]; labelprefix : 'L'; @@ -801,7 +839,7 @@ unit agcpugas; id : as_clang_gas; idtxt : 'CLANG'; asmbin : 'clang'; - asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM'; + asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM'; supported_targets : [system_aarch64_win64]; flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi]; labelprefix : '.L'; -- cgit v1.2.1 From 6781a5fdaea823e589802ca3e8960e62a3765b23 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:12:02 +0000 Subject: Add a second handling of NIL entries in deflist git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49270 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/wasm32/agllvmmc.pas | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/wasm32/agllvmmc.pas b/compiler/wasm32/agllvmmc.pas index 95db60e14b..de9e0a8b99 100644 --- a/compiler/wasm32/agllvmmc.pas +++ b/compiler/wasm32/agllvmmc.pas @@ -112,13 +112,16 @@ implementation list.Concat(tai_functype.create(make_mangledname('FINALIZE$',cur_unit.u.globalsymtable,''),TWasmFuncType.Create([],[]))); end; for i:=0 to cur_unit.u.deflist.Count-1 do - if assigned(cur_unit.u.deflist[i]) and (tdef(cur_unit.u.deflist[i]).typ = procdef) then - begin - proc := tprocdef(cur_unit.u.deflist[i]); - if (not proc.owner.iscurrentunit or (po_external in proc.procoptions)) and - ((proc.paras.Count=0) or (proc.has_paraloc_info in [callerside,callbothsides])) then - thlcgwasm(hlcg).g_procdef(list,proc); - end; + begin + def:=tdef(cur_unit.u.deflist[i]); + if assigned(def) and (tdef(def).typ = procdef) then + begin + proc := tprocdef(def); + if (not proc.owner.iscurrentunit or (po_external in proc.procoptions)) and + ((proc.paras.Count=0) or (proc.has_paraloc_info in [callerside,callbothsides])) then + thlcgwasm(hlcg).g_procdef(list,proc); + end; + end; cur_unit:=tused_unit(cur_unit.Next); end; WriteTree(list); -- cgit v1.2.1 From b17ec5f5891689aea80ca036d221d277bec8c65a Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:14:27 +0000 Subject: Add .force_thumb pseudo-directive support forarm reader git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49271 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/aasmtai.pas | 3 ++- compiler/arm/raarmgas.pas | 6 ++++++ compiler/assemble.pas | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/aasmtai.pas b/compiler/aasmtai.pas index 84049cae9a..fec178a2cf 100644 --- a/compiler/aasmtai.pas +++ b/compiler/aasmtai.pas @@ -402,7 +402,7 @@ interface { supported by recent clang-based assemblers for data-in-code } asd_data_region, asd_end_data_region, { ARM } - asd_thumb_func,asd_code, + asd_thumb_func,asd_code,asd_force_thumb, { restricts the assembler only to those instructions, which are available on the specified CPU; this represents directives such as NASM's 'CPU 686' or MASM/TASM's '.686p'. Might not be supported by @@ -452,6 +452,7 @@ interface { ARM } 'thumb_func', 'code', + 'force_thumb', 'cpu', { for the OMF object format } 'omf_line', diff --git a/compiler/arm/raarmgas.pas b/compiler/arm/raarmgas.pas index ef7a26a2fd..56ba931571 100644 --- a/compiler/arm/raarmgas.pas +++ b/compiler/arm/raarmgas.pas @@ -151,6 +151,7 @@ Unit raarmgas; function tarmattreader.is_targetdirective(const s: string): boolean; begin case s of + '.force_thumb', '.thumb_func', '.code', '.thumb_set': @@ -1464,6 +1465,11 @@ Unit raarmgas; begin consume(AS_TARGET_DIRECTIVE); curList.concat(tai_directive.create(asd_thumb_func,'')); + end; + '.force_thumb': + begin + consume(AS_TARGET_DIRECTIVE); + curList.concat(tai_directive.create(asd_force_thumb,'')); end else inherited HandleTargetDirective; diff --git a/compiler/assemble.pas b/compiler/assemble.pas index aab41ccc2b..56b8426401 100644 --- a/compiler/assemble.pas +++ b/compiler/assemble.pas @@ -1719,6 +1719,11 @@ Implementation {$ifdef ARM} asd_thumb_func: ObjData.ThumbFunc:=true; + asd_force_thumb: + begin + ObjData.ThumbFunc:=true; + Code16:=true; + end; asd_code: begin { ai_directive(hp).name can be only 16 or 32, this is checked by the reader } @@ -1924,6 +1929,9 @@ Implementation asd_thumb_func: { ignore for now, but should be added} ; + asd_force_thumb: + { ignore for now, but should be added} + ; asd_code: { ignore for now, but should be added} ; -- cgit v1.2.1 From adf6fe1a1c2d65db849fb1938d570bc5c6c4504b Mon Sep 17 00:00:00 2001 From: mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:16:28 +0000 Subject: fcl-passrc: fixed (intf as tobject).ClassType, issue 38805 git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49272 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-passrc/src/pasresolver.pp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/fcl-passrc/src/pasresolver.pp b/packages/fcl-passrc/src/pasresolver.pp index e726e9a5c5..b13ffd7baa 100644 --- a/packages/fcl-passrc/src/pasresolver.pp +++ b/packages/fcl-passrc/src/pasresolver.pp @@ -25546,6 +25546,7 @@ function TPasResolver.ResolvedElIsClassOrRecordInstance( const ResolvedEl: TPasResolverResult): boolean; var TypeEl: TPasType; + C: TClass; begin Result:=false; if ResolvedEl.BaseType<>btContext then exit; @@ -25558,10 +25559,14 @@ begin else if TypeEl.ClassType=TPasRecordType then else exit; - if (ResolvedEl.IdentEl is TPasVariable) - or (ResolvedEl.IdentEl.ClassType=TPasArgument) - or (ResolvedEl.IdentEl.ClassType=TPasResultElement) then - exit(true); + if ResolvedEl.IdentEl<>nil then + begin + C:=ResolvedEl.IdentEl.ClassType; + if C.InheritsFrom(TPasVariable) + or (C=TPasArgument) + or (C=TPasResultElement) then + exit(true); + end; end; function TPasResolver.GetResolver(El: TPasElement): TPasResolver; -- cgit v1.2.1 From fd6a082b1ce248125b78ca99a6b41f2103a82993 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:50:53 +0000 Subject: Avoid invalid typecast if hp is not an instruction git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49273 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/arm/rgcpu.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/arm/rgcpu.pas b/compiler/arm/rgcpu.pas index 65a7fda72f..7fa6c16e2d 100644 --- a/compiler/arm/rgcpu.pas +++ b/compiler/arm/rgcpu.pas @@ -400,10 +400,11 @@ unit rgcpu; level := 0; while assigned(hp) do begin - if IsIT(taicpu(hp).opcode) then - break - else if hp.typ=ait_instruction then - inc(level); + if hp.typ=ait_instruction then + if IsIT(taicpu(hp).opcode) then + break + else + inc(level); hp:=tai(hp.Previous); end; -- cgit v1.2.1 From 81ad885b51fa3fbce3aacfee894d7e2dbeb362f0 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Mon, 26 Apr 2021 21:51:42 +0000 Subject: Disable overflow/range check in some part of the arm code git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49274 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/arm/aasmcpu.pas | 4 ++++ compiler/arm/cpubase.pas | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/arm/aasmcpu.pas b/compiler/arm/aasmcpu.pas index 443681430a..c8cb8ff3ce 100644 --- a/compiler/arm/aasmcpu.pas +++ b/compiler/arm/aasmcpu.pas @@ -1621,6 +1621,9 @@ implementation end; end; +{$push} +{ Disable range and overflow checking here } +{$R-}{$Q-} procedure fix_invalid_imms(list: TAsmList); var curtai: tai; @@ -1669,6 +1672,7 @@ implementation end; end; +{$pop} procedure gather_it_info(list: TAsmList); var diff --git a/compiler/arm/cpubase.pas b/compiler/arm/cpubase.pas index 9432c122c7..08189c4202 100644 --- a/compiler/arm/cpubase.pas +++ b/compiler/arm/cpubase.pas @@ -605,6 +605,9 @@ unit cpubase; end; +{$push} +{ Disable range and overflow checking here } +{$R-}{$Q-} function is_thumb32_imm(d: aint): boolean; var t : aint; @@ -639,9 +642,6 @@ unit cpubase; end; end; -{$push} -{ Disable range and overflow checking here } -{$R-}{$Q-} function is_continuous_mask(d : aword;var lsb, width: byte) : boolean; var msb : byte; -- cgit v1.2.1 From b1887675b62350c6180672a934da4d531b699a93 Mon Sep 17 00:00:00 2001 From: karoly <karoly@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 06:25:13 +0000 Subject: m68k: fixed a comment. no functional change git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49275 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/m68k/ag68kvasm.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/m68k/ag68kvasm.pas b/compiler/m68k/ag68kvasm.pas index a37e24fe35..7c1a7bf9bc 100644 --- a/compiler/m68k/ag68kvasm.pas +++ b/compiler/m68k/ag68kvasm.pas @@ -96,8 +96,7 @@ unit ag68kvasm; result:=asminfo^.asmcmd; case target_info.system of - { a.out doesn't support named sections, a.out is limited - (no named sections) lets use ELF for interoperability } + { a.out doesn't support named sections, lets use ELF for interoperability } system_m68k_amiga, system_m68k_atari, system_m68k_sinclairql: objtype:='-Felf'; -- cgit v1.2.1 From 64aefccc4c413f011e7d62ed717c8d69286b809a Mon Sep 17 00:00:00 2001 From: michael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 11:16:58 +0000 Subject: * Make some properties public git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49276 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-web/src/base/custhttpapp.pp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/fcl-web/src/base/custhttpapp.pp b/packages/fcl-web/src/base/custhttpapp.pp index 58bb5a6842..b196db160e 100644 --- a/packages/fcl-web/src/base/custhttpapp.pp +++ b/packages/fcl-web/src/base/custhttpapp.pp @@ -76,7 +76,6 @@ Type Procedure InitResponse(AResponse : TResponse); override; function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; override; Function CreateServer : TEmbeddedHttpServer; virtual; - Property HTTPServer : TEmbeddedHttpServer Read FServer; Public Procedure Run; override; Procedure Terminate; override; @@ -104,6 +103,8 @@ Type Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL; // HostName to use when using SSL Property HostName : String Read GetHostName Write SetHostName; + // Access to server so you can set certificate data + Property HTTPServer : TEmbeddedHttpServer Read FServer; end; { TCustomHTTPApplication } @@ -111,6 +112,7 @@ Type TCustomHTTPApplication = Class(TCustomWebApplication) private procedure FakeConnect; + function GetCertificateData: TCertificateData; function GetHostName: String; function GetIdle: TNotifyEvent; function GetIDleTimeOut: Cardinal; @@ -133,9 +135,10 @@ Type procedure SetUseSSL(AValue: Boolean); protected function InitializeWebHandler: TWebHandler; override; - Function HTTPHandler : TFPHTTPServerHandler; Public procedure Terminate; override; + // Access to HTTP handler + Function HTTPHandler : TFPHTTPServerHandler; Property Address : string Read GetAddress Write SetAddress; Property Port : Word Read GetPort Write SetPort Default 80; // Max connections on queue (for Listen call) @@ -154,6 +157,8 @@ Type Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL; // Hostname to use when using SSL Property HostName : String Read GetHostName Write SetHostName; + // Access to certificate data + Property CertificateData : TCertificateData Read GetCertificateData; end; @@ -296,6 +301,11 @@ begin end end; +function TCustomHTTPApplication.GetCertificateData: TCertificateData; +begin + Result:=HTTPHandler.HTTPServer.CertificateData; +end; + function TCustomHTTPApplication.GetHostName: String; begin Result:=HTTPHandler.HostName; -- cgit v1.2.1 From bfc3606704a7cb4c77a9d999ed6f8419d01e6244 Mon Sep 17 00:00:00 2001 From: michael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 11:30:53 +0000 Subject: * Forgot to include sslbase git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49277 3ad0048d-3df7-0310-abae-a5850022a9f2 --- packages/fcl-web/src/base/custhttpapp.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fcl-web/src/base/custhttpapp.pp b/packages/fcl-web/src/base/custhttpapp.pp index b196db160e..d51a9efff1 100644 --- a/packages/fcl-web/src/base/custhttpapp.pp +++ b/packages/fcl-web/src/base/custhttpapp.pp @@ -21,7 +21,7 @@ unit custhttpapp; Interface uses - Classes, SysUtils, httpdefs, custweb, ssockets, fphttpserver; + Classes, SysUtils, httpdefs, custweb, ssockets, fphttpserver, sslbase; Type TCustomHTTPApplication = Class; -- cgit v1.2.1 From 140cd7445bcd9103090414e9223d11354a8de1c9 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 14:01:35 +0000 Subject: Avoid range check error inside genitem_thumb2 by changing local variable i type git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49278 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/arm/narmset.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/arm/narmset.pas b/compiler/arm/narmset.pas index 4d0c2cb5ca..3bb9ecd471 100644 --- a/compiler/arm/narmset.pas +++ b/compiler/arm/narmset.pas @@ -191,7 +191,7 @@ implementation procedure genitem_thumb2(list:TAsmList;t : pcaselabel); var - i : aint; + i : int64; begin if assigned(t^.less) then genitem_thumb2(list,t^.less); -- cgit v1.2.1 From 1cf576df7b09c8e02c6608281807fd95b6813160 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 14:20:09 +0000 Subject: Make sure nf_usercode_entry get transferred inside firstpass procedure git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49279 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/pass_1.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/pass_1.pas b/compiler/pass_1.pas index 2ac00dbc43..4d543a8e31 100644 --- a/compiler/pass_1.pas +++ b/compiler/pass_1.pas @@ -189,6 +189,7 @@ implementation { should the node be replaced? } if assigned(hp) then begin + hp.flags := hp.flags + (p.flags * [nf_usercode_entry]); p.free; { switch to new node } p:=hp; -- cgit v1.2.1 From 6b13fc7eb4cf5316977817b48ac8e28729e11228 Mon Sep 17 00:00:00 2001 From: pierre <pierre@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 14:52:22 +0000 Subject: Set string length before calling move to avoid problems with global data analysis on systems using C library git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49280 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/assemble.pas | 2 +- compiler/ogcoff.pas | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/assemble.pas b/compiler/assemble.pas index 56b8426401..a3798d1bdc 100644 --- a/compiler/assemble.pas +++ b/compiler/assemble.pas @@ -1403,8 +1403,8 @@ Implementation len:=p-pstart; if len>255 then internalerror(200509187); - move(pstart^,hs[1],len); hs[0]:=chr(len); + move(pstart^,hs[1],len); sym:=objdata.symbolref(hs); { Second symbol? } if assigned(relocsym) then diff --git a/compiler/ogcoff.pas b/compiler/ogcoff.pas index 879eb0ca25..e5d9fd0844 100644 --- a/compiler/ogcoff.pas +++ b/compiler/ogcoff.pas @@ -2063,6 +2063,8 @@ const pemagic : array[0..3] of byte = ( FCoffSyms.Read(bosym,sizeof(bosym)); if bosym.Name.Offset.Zeroes<>0 then begin + { Added for sake of global data analysis } + strname[0]:=#0; move(bosym.Name.ShortName,strname[1],8); strname[9]:=#0; strname[0]:=chr(strlen(@strname[1])); @@ -2081,6 +2083,8 @@ const pemagic : array[0..3] of byte = ( FCoffSyms.Read(sym,sizeof(sym)); if plongint(@sym.name)^<>0 then begin + { Added for sake of global data analysis } + strname[0]:=#0; move(sym.name,strname[1],8); strname[9]:=#0; strname[0]:=chr(strlen(@strname[1])); -- cgit v1.2.1 From ae5b0de491a91321675f73eae5db628d068f4e05 Mon Sep 17 00:00:00 2001 From: florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> Date: Tue, 27 Apr 2021 16:36:40 +0000 Subject: * fix compilation of arm compiler on 32 bit hosts git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@49281 3ad0048d-3df7-0310-abae-a5850022a9f2 --- compiler/arm/narmset.pas | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/arm/narmset.pas b/compiler/arm/narmset.pas index 3bb9ecd471..9c0d668134 100644 --- a/compiler/arm/narmset.pas +++ b/compiler/arm/narmset.pas @@ -196,10 +196,18 @@ implementation if assigned(t^.less) then genitem_thumb2(list,t^.less); { fill possible hole } - for i:=last.svalue+1 to t^._low.svalue-1 do - list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,elselabel)); - for i:=t^._low.svalue to t^._high.svalue do - list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,blocklabel(t^.blockid))); + i:=last.svalue+1; + while i<=t^._low.svalue-1 do + begin + list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,elselabel)); + i:=i+1; + end; + i:=t^._low.svalue; + while i<=t^._high.svalue do + begin + list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,blocklabel(t^.blockid))); + i:=i+1; + end; last:=t^._high.svalue; if assigned(t^.greater) then genitem_thumb2(list,t^.greater); -- cgit v1.2.1