diff options
author | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2021-02-07 20:53:59 +0000 |
---|---|---|
committer | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2021-02-07 20:53:59 +0000 |
commit | 605e85d8ae30f0027f1fc8df0de5de18ab210c89 (patch) | |
tree | 2fc78a3ff7ccacfa26d6faf1b7c846ddb1bea79a | |
parent | 611ca8ad56d84d4c163bb8b38c43d683fec3e476 (diff) | |
download | fpc-605e85d8ae30f0027f1fc8df0de5de18ab210c89.tar.gz |
-- Zusammenführen von r48108 bis r48520 in ».«:
A tests/webtbs/uw38385b.pp
A tests/webtbs/tw38351.pp
A tests/webtbs/tw38316.pp
U tests/Makefile
A tests/webtbf/tw37217.pp
A tests/webtbs/tw32139.pp
A tests/webtbs/tw38429.pp
A tests/webtbs/tw38413.pp
A tests/webtbs/uw38385a.pp
A tests/webtbs/tw38390.pp
A tests/webtbs/tw38306.pp
A tests/webtbs/tw38337.pp
C tests/bench/bcase.pp
U rtl/unix/sysutils.pp
U rtl/unix/oscdeclh.inc
U rtl/linux/x86_64/syscall.inc
U rtl/linux/x86_64/si_prc.inc
U rtl/linux/linux.pp
U rtl/linux/m68k/cprt0.as
U rtl/linux/m68k/dllprt0.as
U rtl/linux/mips/cprt0.as
U rtl/linux/mips/prt0.as
U rtl/linux/i386/si_prc.inc
U rtl/linux/si_impl.inc
U rtl/linux/system.pp
U rtl/i386/cpu.pp
U rtl/objpas/sysconst.pp
U rtl/objpas/sysutils/syshelpo.inc
U rtl/amiga/powerpc/execf.inc
U tests/test/units/sysutils/tfile1.pp
A tests/test/units/sysutils/tfileage.pp
A tests/test/units/linux/tfutimesen.pp
U tests/test/units/linux/tstatx.pp
A tests/test/units/linux/tutimensat.pp
A tests/test/cg/tpara4.pp
U tests/test/theapthread.pp
A tests/webtbf/tw24434.pp
A tests/webtbf/tw38287.pp
A tests/webtbs/tw34027.pp
A tests/webtbs/uw38429.pp
A tests/webtbs/tw38412.pp
A tests/webtbs/tw38385.pp
A tests/webtbs/uw38385c.pp
U tests/webtbs/tw37060.pp
A tests/webtbs/tw38339.pp
U tests/Makefile.fpc
U tests/utils/testsuite/utests.pp
U compiler/utils/mkx86inl.pp
U compiler/utils/ppuutils/ppudump.pp
U compiler/nmem.pas
U compiler/msg/errorda.msg
U compiler/msg/errorf.msg
U compiler/msg/errorid.msg
U compiler/msg/errorpli.msg
U compiler/msg/errorru.msg
U compiler/m68k/aoptcpu.pas
U compiler/systems/t_darwin.pas
U compiler/utils/msg2inc.pp
U compiler/utils/Makefile.fpc
U compiler/cfidwarf.pas
U compiler/msg/errord.msg
U compiler/msg/errores.msg
U compiler/msg/errorheu.msg
U compiler/msg/errorpl.msg
U compiler/msg/errorr.msg
U compiler/m68k/cgcpu.pas
U compiler/rgobj.pas
U compiler/Makefile.fpc
U compiler/utils/Makefile
U compiler/ngtcon.pas
U compiler/msg/errorct.msg
U compiler/msg/errore.msg
U compiler/msg/errorhe.msg
U compiler/msg/errorn.msg
U compiler/msg/errorptu.msg
C compiler/msgtxt.inc
C compiler/msgidx.inc
U compiler/systems/t_freertos.pas
U compiler/Makefile
U compiler/utils/mkz80ins.pp
U compiler/aasmcnst.pas
U compiler/ncon.pas
U compiler/msg/errordu.msg
U compiler/msg/errorfi.msg
U compiler/msg/erroriu.msg
U compiler/msg/errorpt.msg
U compiler/msg/errorues.msg
U compiler/ncgvmt.pas
U compiler/systems/t_embed.pas
U compiler/systems/t_bsd.pas
U compiler/dbgcodeview.pas
U compiler/x86/agx86nsm.pas
U compiler/systems/t_win16.pas
U compiler/verbose.pas
U compiler/x86/aasmcpu.pas
U compiler/x86/nx86mat.pas
U compiler/systems/t_amiga.pas
U compiler/x86/cgx86.pas
U compiler/x86/nx86inl.pas
U compiler/systems/t_win.pas
U compiler/x86/cx86mminnr.inc
U compiler/x86/aoptx86.pas
U compiler/x86/nx86set.pas
U compiler/systems.pas
U compiler/avr/navradd.pas
U compiler/avr/raavrgas.pas
U compiler/aarch64/aasmcpu.pas
U compiler/jvm/hlcgcpu.pas
U compiler/jvm/njvmmat.pas
U compiler/psabiehpi.pas
U compiler/options.pas
U compiler/avr/cpupara.pas
U compiler/avr/navrmat.pas
U compiler/aarch64/aoptcpu.pas
U compiler/jvm/njvmmem.pas
U compiler/jvm/njvminl.pas
U compiler/pgenutil.pas
U compiler/globtype.pas
U compiler/avr/cgcpu.pas
U compiler/avr/aoptcpu.pas
U compiler/aarch64/agcpugas.pas
U compiler/jvm/dbgjasm.pas
U compiler/jvm/cpubase.pas
U compiler/ogomf.pas
U compiler/i8086/symcpu.pas
U compiler/x86/rax86.pas
U compiler/arm/aoptcpu.pas
U compiler/avr/agavrgas.pas
U compiler/avr/rgcpu.pas
U compiler/aarch64/cgcpu.pas
U compiler/jvm/agjasmin.pas
U compiler/nflw.pas
U compiler/i8086/n8086mem.pas
U packages/graph/src/inc/graph.tex
A packages/fcl-net/tests
U compiler/i8086/n8086tcon.pas
U compiler/ncginl.pas
U compiler/symdef.pas
U compiler/i8086/cpupara.pas
U compiler/nbas.pas
U compiler/scandir.pas
U compiler/hlcgobj.pas
U compiler/nadd.pas
U compiler/psub.pas
U compiler/armgen/aoptarm.pas
U compiler/aggas.pas
U compiler/optloop.pas
U compiler/scanner.pas
U compiler/x86_64/nx64mat.pas
U compiler/ogbase.pas
U compiler/i386/aoptcpu.pas
U packages/fcl-passrc/src/pasresolver.pp
U packages/pastojs/src/fppas2js.pp
U packages/rtl-objpas/src/inc/dateutil.inc
A packages/fcl-net/tests/netdbtest.pp
U compiler/x86_64/aoptcpu.pas
U compiler/ncal.pas
U compiler/fpcdefs.inc
U packages/pastojs/tests/tcmodules.pas
U packages/rtl-objpas/src/inc/variants.pp
U packages/fcl-net/src/netdb.pp
A packages/pasjpeg/examples/demo.lpi
U compiler/x86_64/cpupara.pas
U compiler/dbgstabs.pas
U compiler/aoptobj.pas
U packages/fcl-passrc/tests/tcresolver.pas
U packages/pastojs/src/pas2jspcucompiler.pp
U packages/fcl-base/src/bufstream.pp
U packages/fcl-stl/src/gdeque.pp
U compiler/x86_64/cpuelf.pas
U compiler/ncnv.pas
U compiler/pdecsub.pas
U packages/fcl-passrc/src/pparser.pp
U packages/pastojs/src/pas2jsfiler.pp
U packages/fcl-base/src/eventlog.pp
A packages/fcl-net/tests/tresolvertests.pp
U packages/pasjpeg/examples/example.pas
U packages/fcl-registry/tests/Makefile
U packages/fcl-registry/src/regini.inc
U packages/fcl-db/src/sqldb/interbase/ibconnection.pp
A packages/fcl-registry/tests/tregtestframework.pp
U packages/fcl-registry/fpmake.pp
U packages/fcl-registry/src/winreg.inc
U packages/fcl-registry/tests/tregistry2.pp
A packages/fcl-registry/tests/regtestbasics.pp
U packages/fcl-registry/src/xmlreg.pp
A packages/fcl-registry/tests/regtcxmlreg.pp
U packages/fcl-registry/tests/Makefile.fpc
D packages/fcl-registry/tests/regtestframework.pp
D packages/fcl-registry/tests/testbasics.pp
D packages/fcl-registry/tests/tcxmlreg.pp
U packages/fcl-registry/src/registry.pp
U packages/rtl-extra/fpmake.pp
U utils/fpdoc/fpdoc.pp
U utils/fpdoc/dw_html.pp
U utils/fpdoc/mkfpdoc.pp
U utils/fpdoc/dw_latex.pp
U utils/fpdoc/dw_xml.pp
U utils/fpdoc/fpmake.pp
U packages/fpmkunit/src/fpmkunit.pp
U utils/fpdoc/dw_chm.pp
U utils/fpdoc/dw_basehtml.pp
A utils/fpdoc/fpdocstrs.pp
U utils/fpdoc/dw_dxml.pp
U utils/fpdoc/dw_txt.pp
U utils/fpdoc/fpdocxmlopts.pas
U packages/fcl-db/src/sqldb/sqldb.pp
U packages/fv/src/views.pas
U utils/fpdoc/dwriter.pp
U utils/fpdoc/fpdoc.lpi
U utils/fpdoc/dw_basemd.pp
U utils/fpdoc/dw_man.pp
U utils/fpdoc/fpdocproj.pas
U packages/fcl-db/src/sqldb/mysql/mysqlconn.inc
U packages/rtl-extra/src/bsd/osdefs.inc
U utils/fpdoc/dw_markdown.pp
U utils/fpdoc/fpdocclasstree.pp
U utils/fpdoc/dglobals.pp
U utils/fpdoc/dw_linrtf.pp
U utils/fpdoc/dwlinear.pp
U utils/pas2js/dist/rtl.js
U utils/fpdoc/fpclasschart.pp
U utils/fpdoc/dw_ipflin.pas
U utils/fpdoc/makeskel.pp
-- Aufzeichnung der Informationen für Zusammenführung von r47033 bis r48520 in ».«:
U .
-- Aufzeichnung der Informationen für Zusammenführung von r47033 bis r48520 in »rtl«:
U rtl
Konfliktübersicht:
Textkonflikte: 3
Konfliktübersicht:
Textkonflikte: 3
git-svn-id: https://svn.freepascal.org/svn/fpc/branches/tg74@48521 3ad0048d-3df7-0310-abae-a5850022a9f2
218 files changed, 11111 insertions, 2698 deletions
diff --git a/avx512-0037785/compiler/Makefile b/avx512-0037785/compiler/Makefile index 3bf6972579..950d084474 100644 --- a/avx512-0037785/compiler/Makefile +++ b/avx512-0037785/compiler/Makefile @@ -4640,6 +4640,9 @@ ifdef CMP override DIFF:=$(CMP) -i218 endif endif +ifeq ($(OS_TARGET), darwin) +CODESIGN?=$(strip $(wildcard $(addsuffix /codesign,$(SEARCHPATH)))) +endif ifneq ($(CYCLELEVEL),1) ifndef ALLOW_WARNINGS override LOCALOPT+=-Sew @@ -4941,7 +4944,11 @@ ifdef OLDFPC ifneq ($(OS_TARGET),darwin) DIFFRESULT:=$(shell $(DIFF) $(OLDFPC) $(FPC)) else -DIFFRESULT:=$(shell cp $(OLDFPC) $(OLDFPC).tmp; cp $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; rm $(OLDFPC).tmp $(FPC).tmp) +ifneq ($(CODESIGN),) +DIFFRESULT:=$(shell $(COPY) $(OLDFPC) $(OLDFPC).tmp; $(COPY) $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(CODESIGN) --remove-signature $(OLDFPC).tmp; codesign --remove-signature $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; $(RMPROG) $(OLDFPC).tmp $(FPC).tmp) +else +DIFFRESULT:=$(shell $(COPY) $(OLDFPC) $(OLDFPC).tmp; $(COPY) $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; $(RMPROG) $(OLDFPC).tmp $(FPC).tmp) +endif endif else DIFFRESULT=Not equal @@ -4980,7 +4987,20 @@ endif $(MAKE) tempclean $(MAKE) $(TEMPNAME3) $(MAKE) 'FPC=$(BASEDIR)/$(TEMPNAME3PREFIX)$(TEMPNAME3)' 'OLDFPC=$(BASEDIR)/$(TEMPNAME2)' next CYCLELEVEL=4 +ifneq ($(OS_TARGET), darwin) $(DIFF) $(TEMPNAME3) $(EXENAME) +else + $(COPY) $(TEMPNAME3) $(TEMPNAME3).tmp + $(COPY) $(EXENAME) $(EXENAME).tmp + strip -no_uuid $(TEMPNAME3).tmp + strip -no_uuid $(EXENAME).tmp +ifneq ($(CODESIGN),) + $(CODESIGN) --remove-signature $(TEMPNAME3).tmp + $(CODESIGN) --remove-signature $(EXENAME).tmp +endif + $(DIFF) $(TEMPNAME3).tmp $(EXENAME).tmp + rm $(TEMPNAME3).tmp $(EXENAME).tmp +endif $(MAKE) $(addsuffix _all,$(TARGET_DIRS)) 'FPC=$(BASEDIR)/$(EXENAMEPREFIX)$(EXENAME)' $(MAKE) wpocycle $(MAKE) echotime diff --git a/avx512-0037785/compiler/Makefile.fpc b/avx512-0037785/compiler/Makefile.fpc index a3852109dc..f1c6e501d2 100644 --- a/avx512-0037785/compiler/Makefile.fpc +++ b/avx512-0037785/compiler/Makefile.fpc @@ -438,6 +438,10 @@ override DIFF:=$(CMP) -i218 endif endif +ifeq ($(OS_TARGET), darwin) +CODESIGN?=$(strip $(wildcard $(addsuffix /codesign,$(SEARCHPATH)))) +endif + # Use -Sew option by default # Allow disabling by setting ALLOW_WARNINGS=1 ifneq ($(CYCLELEVEL),1) @@ -878,7 +882,11 @@ ifdef OLDFPC ifneq ($(OS_TARGET),darwin) DIFFRESULT:=$(shell $(DIFF) $(OLDFPC) $(FPC)) else -DIFFRESULT:=$(shell cp $(OLDFPC) $(OLDFPC).tmp; cp $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; rm $(OLDFPC).tmp $(FPC).tmp) +ifneq ($(CODESIGN),) +DIFFRESULT:=$(shell $(COPY) $(OLDFPC) $(OLDFPC).tmp; $(COPY) $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(CODESIGN) --remove-signature $(OLDFPC).tmp; codesign --remove-signature $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; $(RMPROG) $(OLDFPC).tmp $(FPC).tmp) +else +DIFFRESULT:=$(shell $(COPY) $(OLDFPC) $(OLDFPC).tmp; $(COPY) $(FPC) $(FPC).tmp; strip -no_uuid $(OLDFPC).tmp; strip -no_uuid $(FPC).tmp; $(DIFF) $(OLDFPC).tmp $(FPC).tmp; $(RMPROG) $(OLDFPC).tmp $(FPC).tmp) +endif endif else DIFFRESULT=Not equal @@ -922,7 +930,20 @@ endif $(MAKE) tempclean $(MAKE) $(TEMPNAME3) $(MAKE) 'FPC=$(BASEDIR)/$(TEMPNAME3PREFIX)$(TEMPNAME3)' 'OLDFPC=$(BASEDIR)/$(TEMPNAME2)' next CYCLELEVEL=4 +ifneq ($(OS_TARGET), darwin) $(DIFF) $(TEMPNAME3) $(EXENAME) +else + $(COPY) $(TEMPNAME3) $(TEMPNAME3).tmp + $(COPY) $(EXENAME) $(EXENAME).tmp + strip -no_uuid $(TEMPNAME3).tmp + strip -no_uuid $(EXENAME).tmp +ifneq ($(CODESIGN),) + $(CODESIGN) --remove-signature $(TEMPNAME3).tmp + $(CODESIGN) --remove-signature $(EXENAME).tmp +endif + $(DIFF) $(TEMPNAME3).tmp $(EXENAME).tmp + rm $(TEMPNAME3).tmp $(EXENAME).tmp +endif $(MAKE) $(addsuffix _all,$(TARGET_DIRS)) 'FPC=$(BASEDIR)/$(EXENAMEPREFIX)$(EXENAME)' $(MAKE) wpocycle $(MAKE) echotime diff --git a/avx512-0037785/compiler/aarch64/aasmcpu.pas b/avx512-0037785/compiler/aarch64/aasmcpu.pas index ba8e3001be..49e66eb606 100644 --- a/avx512-0037785/compiler/aarch64/aasmcpu.pas +++ b/avx512-0037785/compiler/aarch64/aasmcpu.pas @@ -1018,6 +1018,7 @@ implementation A_TST, A_FCMP,A_FCMPE, A_CBZ,A_CBNZ, + A_PRFM,A_PRFUM, A_RET: result:=operand_read; A_STR,A_STUR: @@ -1026,14 +1027,6 @@ implementation else { check for pre/post indexed in spilling_get_operation_type_ref } result:=operand_read; - A_STLXP, - A_STLXR, - A_STXP, - A_STXR: - if opnr=0 then - result:=operand_write - else - result:=operand_read; A_STP: begin if opnr in [0,1] then @@ -1102,12 +1095,21 @@ implementation A_FCVTZS, A_SDIV, A_SMULL, + A_STLXP, + A_STLXR, + A_STXP, + A_STXR, A_SUB, + A_SXTB, + A_SXTH, + A_SXTW, A_UBFIZ, A_UBFX, A_UCVTF, A_UDIV, - A_UMULL: + A_UMULL, + A_UXTB, + A_UXTH: if opnr=0 then result:=operand_write else diff --git a/avx512-0037785/compiler/aarch64/agcpugas.pas b/avx512-0037785/compiler/aarch64/agcpugas.pas index 35eafef1e7..d6fd59ac76 100644 --- a/avx512-0037785/compiler/aarch64/agcpugas.pas +++ b/avx512-0037785/compiler/aarch64/agcpugas.pas @@ -252,7 +252,6 @@ unit agcpugas; lastsym : tai_symbol; lastsec : tai_section; inprologue, - inhandlerdata, deleteai : boolean; totalcount, instrcount, @@ -265,7 +264,6 @@ unit agcpugas; sehlist, tmplist : TAsmList; xdatasym : tasmsymbol; - unwindread, unwindrec : longword; begin if not assigned(list) then @@ -278,7 +276,6 @@ unit agcpugas; instrcount:=0; datacount:=0; unwinddata:=nil; - inhandlerdata:=false; inprologue:=false; handlerdata:=nil; handlerdataidx:=0; diff --git a/avx512-0037785/compiler/aarch64/aoptcpu.pas b/avx512-0037785/compiler/aarch64/aoptcpu.pas index e682bbdda7..4ef898284e 100644 --- a/avx512-0037785/compiler/aarch64/aoptcpu.pas +++ b/avx512-0037785/compiler/aarch64/aoptcpu.pas @@ -568,7 +568,6 @@ Implementation ThisRegister: TRegister; OffsetVal, ValidOffset, MinOffset, MaxOffset: asizeint; TargetOpcode: TAsmOp; - Breakout: Boolean; begin Result := False; ThisRegister := taicpu(p).oper[0]^.reg; @@ -621,8 +620,6 @@ Implementation if (taicpu(hp1).opcode = taicpu(p).opcode) then begin - Breakout := False; - if (taicpu(hp1).oppostfix = PF_NONE) and { Registers need to be the same size } (getsubreg(ThisRegister) = getsubreg(taicpu(hp1).oper[0]^.reg)) and @@ -754,8 +751,6 @@ Implementation function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean; - var - hp1: tai; begin result := false; if p.typ=ait_instruction then @@ -817,8 +812,6 @@ Implementation function TCpuAsmOptimizer.PeepHoleOptPass2Cpu(var p: tai): boolean; - var - hp1: tai; begin result := false; if p.typ=ait_instruction then diff --git a/avx512-0037785/compiler/aarch64/cgcpu.pas b/avx512-0037785/compiler/aarch64/cgcpu.pas index 9f0917e5a7..2036e99534 100644 --- a/avx512-0037785/compiler/aarch64/cgcpu.pas +++ b/avx512-0037785/compiler/aarch64/cgcpu.pas @@ -587,6 +587,9 @@ implementation manipulated_a: tcgint; leftover_a: word; begin +{$ifdef extdebug} + list.concat(tai_comment.Create(strpnew('Generating constant ' + tostr(a)))); +{$endif extdebug} case a of { Small positive number } $0..$FFFF: diff --git a/avx512-0037785/compiler/aasmcnst.pas b/avx512-0037785/compiler/aasmcnst.pas index 4d106564fa..d37cd74b76 100644 --- a/avx512-0037785/compiler/aasmcnst.pas +++ b/avx512-0037785/compiler/aasmcnst.pas @@ -427,6 +427,10 @@ type function queue_subscriptn_multiple_by_name(def: tabstractrecorddef; const fields: array of TIDString): tdef; { queue a type conversion operation } procedure queue_typeconvn(fromdef, todef: tdef); virtual; + { queue a add operation } + procedure queue_addn(def: tdef; const index: tconstexprint); virtual; + { queue a sub operation } + procedure queue_subn(def: tdef; const index: tconstexprint); virtual; { finalise the queue (so a new one can be created) and flush the previously queued operations, applying them in reverse order on a...} { ... procdef } @@ -2080,6 +2084,18 @@ implementation end; + procedure ttai_typedconstbuilder.queue_addn(def: tdef; const index: tconstexprint); + begin + inc(fqueue_offset,def.size*int64(index)); + end; + + + procedure ttai_typedconstbuilder.queue_subn(def: tdef; const index: tconstexprint); + begin + dec(fqueue_offset,def.size*int64(index)); + end; + + procedure ttai_typedconstbuilder.queue_subscriptn(def: tabstractrecorddef; vs: tfieldvarsym); begin inc(fqueue_offset,vs.fieldoffset); diff --git a/avx512-0037785/compiler/aggas.pas b/avx512-0037785/compiler/aggas.pas index efd565fdc3..710ec54652 100644 --- a/avx512-0037785/compiler/aggas.pas +++ b/avx512-0037785/compiler/aggas.pas @@ -497,7 +497,6 @@ implementation procedure TGNUAssembler.WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder;secalign:longint;secflags:TSectionFlags=[];secprogbits:TSectionProgbits=SPB_None); var s : string; - secflag: TSectionFlag; usesectionprogbits, usesectionflags: boolean; begin diff --git a/avx512-0037785/compiler/aoptobj.pas b/avx512-0037785/compiler/aoptobj.pas index fd14f81674..8b10fd0091 100644 --- a/avx512-0037785/compiler/aoptobj.pas +++ b/avx512-0037785/compiler/aoptobj.pas @@ -1382,12 +1382,10 @@ Unit AoptObj; removedSomething := false; firstRemovedWasAlloc := false; {$ifdef allocregdebug} - hp := tai_comment.Create(strpnew('allocating '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+ - ' from here...')); - insertllitem(asml,p1.previous,p1,hp); - hp := tai_comment.Create(strpnew('allocated '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+ - ' till here...')); - insertllitem(asml,p2,p2.next,hp); + hp := tai_comment.Create(strpnew('allocating '+std_regname(reg)+' from here...')); + insertllitem(p1.previous,p1,hp); + hp := tai_comment.Create(strpnew('allocated '+std_regname(reg)+' till here...')); + insertllitem(p2,p2.next,hp); {$endif allocregdebug} { do it the safe way: always allocate the full super register, as we do no register re-allocation in the peephole optimizer, diff --git a/avx512-0037785/compiler/arm/aoptcpu.pas b/avx512-0037785/compiler/arm/aoptcpu.pas index 3adb81644e..2b798b18c9 100644 --- a/avx512-0037785/compiler/arm/aoptcpu.pas +++ b/avx512-0037785/compiler/arm/aoptcpu.pas @@ -59,6 +59,7 @@ Type function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override; function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override; + function OptPass1And(var p: tai): Boolean; override; { There's optimisation code that's general for all ARM platforms } protected function LookForPreindexedPattern(p: taicpu): boolean; function LookForPostindexedPattern(p: taicpu): boolean; @@ -67,7 +68,6 @@ Type { Individual optimisation routines } function OptPass1DataCheckMov(var p: tai): Boolean; function OptPass1ADDSUB(var p: tai): Boolean; - function OptPass1And(var p: tai): Boolean; override; { There's optimisation code that's general for all ARM platforms } function OptPass1CMP(var p: tai): Boolean; function OptPass1LDR(var p: tai): Boolean; function OptPass1STM(var p: tai): Boolean; @@ -540,7 +540,6 @@ Implementation function TCpuAsmOptimizer.OptPass1ADDSUB(var p: tai): Boolean; var hp1,hp2: tai; - oldreg: tregister; begin Result := OptPass1DataCheckMov(p); @@ -621,7 +620,7 @@ Implementation function TCpuAsmOptimizer.OptPass1MUL(var p: tai): Boolean; var - hp1,hp2: tai; + hp1: tai; oldreg: tregister; begin Result := OptPass1DataCheckMov(p); @@ -1099,7 +1098,7 @@ Implementation function TCpuAsmOptimizer.OptPass1MOV(var p: tai): Boolean; var - hp1, hpfar1, hp2, hp3: tai; + hp1, hpfar1, hp2: tai; i, i2: longint; tempop: tasmop; dealloc: tai_regalloc; diff --git a/avx512-0037785/compiler/armgen/aoptarm.pas b/avx512-0037785/compiler/armgen/aoptarm.pas index 2581f34a5b..b0f3b0f0ae 100644 --- a/avx512-0037785/compiler/armgen/aoptarm.pas +++ b/avx512-0037785/compiler/armgen/aoptarm.pas @@ -531,6 +531,11 @@ Implementation { Instruction will become mov r1,r1 } DebugMsg('Peephole Optimization: Mov2None 2 done', next_hp); + { Allocate r1 between the instructions; not doing + so may cause problems when removing superfluous + MOVs later (i38055) } + AllocRegBetween(taicpu(p).oper[1]^.reg, p, next_hp, UsedRegs); + if (next_hp = hp1) then { Don't let hp1 become a dangling pointer } hp1 := nil; @@ -902,8 +907,8 @@ Implementation { reg1 might not be modified inbetween } not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then begin - DebugMsg('Peephole SxtbAndImm2Sxtb done', p); - taicpu(hp1).opcode:=A_SXTB; + DebugMsg('Peephole SxtbAndImm2Uxtb done', p); + taicpu(hp1).opcode:=A_UXTB; taicpu(hp1).ops:=2; taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg); GetNextInstruction(p,hp2); @@ -913,7 +918,7 @@ Implementation result:=true; end else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and - RemoveSuperfluousMove(p, hp1, 'SxtbMov2Data') then + RemoveSuperfluousMove(p, hp1, 'UxtbMov2Data') then Result:=true; end; @@ -983,7 +988,7 @@ Implementation and reg3,reg2,#65535 dealloc reg2 to - sxth reg3,reg1 + uxth reg3,reg1 } else if MatchInstruction(p, A_SXTH, [C_None], [PF_None]) and (taicpu(p).ops=2) and @@ -997,8 +1002,8 @@ Implementation { reg1 might not be modified inbetween } not(RegModifiedBetween(taicpu(p).oper[1]^.reg,p,hp1)) then begin - DebugMsg('Peephole SxthAndImm2Sxth done', p); - taicpu(hp1).opcode:=A_SXTH; + DebugMsg('Peephole SxthAndImm2Uxth done', p); + taicpu(hp1).opcode:=A_UXTH; taicpu(hp1).ops:=2; taicpu(hp1).loadReg(1,taicpu(p).oper[1]^.reg); GetNextInstruction(p, hp1); @@ -1008,7 +1013,7 @@ Implementation result:=true; end else if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and - RemoveSuperfluousMove(p, hp1, 'SxthMov2Data') then + RemoveSuperfluousMove(p, hp1, 'UxthMov2Data') then Result:=true; end; diff --git a/avx512-0037785/compiler/avr/agavrgas.pas b/avx512-0037785/compiler/avr/agavrgas.pas index fc62854f69..d4df03db2a 100644 --- a/avx512-0037785/compiler/avr/agavrgas.pas +++ b/avx512-0037785/compiler/avr/agavrgas.pas @@ -154,8 +154,6 @@ unit agavrgas; function getopstr(const o:toper) : string; var hs : string; - first : boolean; - r : tsuperregister; begin case o.typ of top_reg: diff --git a/avx512-0037785/compiler/avr/aoptcpu.pas b/avx512-0037785/compiler/avr/aoptcpu.pas index 031633d92f..3a99b9864b 100644 --- a/avx512-0037785/compiler/avr/aoptcpu.pas +++ b/avx512-0037785/compiler/avr/aoptcpu.pas @@ -258,7 +258,6 @@ Implementation var hp1, hp2, hp3: tai; - s: string; begin result:=false; diff --git a/avx512-0037785/compiler/avr/cgcpu.pas b/avx512-0037785/compiler/avr/cgcpu.pas index 4722405541..72402d6552 100644 --- a/avx512-0037785/compiler/avr/cgcpu.pas +++ b/avx512-0037785/compiler/avr/cgcpu.pas @@ -264,7 +264,6 @@ unit cgcpu; var i,j : longint; hp : PCGParaLocation; - ref: treference; tmpreg: TRegister; begin if not(tcgsize2size[paraloc.Size] in [1..4]) then @@ -310,7 +309,7 @@ unit cgcpu; procedure tcgavr.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara); var - tmpref, ref: treference; + tmpref: treference; location: pcgparalocation; sizeleft: tcgint; i: Integer; @@ -327,7 +326,6 @@ unit cgcpu; a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register); LOC_REFERENCE: begin - ref:=tmpref; for i:=1 to sizeleft do begin tmpreg:=getintregister(list,OS_8); @@ -417,7 +415,7 @@ unit cgcpu; procedure tcgavr.a_op_const_reg_reg_internal(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src,srchi,dst,dsthi: tregister); var - tmpSrc, tmpDst, countreg: TRegister; + countreg: TRegister; b, b2, i, j: byte; s1, s2, t1: integer; l1: TAsmLabel; @@ -574,10 +572,7 @@ unit cgcpu; countreg, tmpreg: tregister; i : integer; - instr : taicpu; - paraloc1,paraloc2 : TCGPara; l1,l2 : tasmlabel; - pd : tprocdef; hovloc: tlocation; { NextRegDst* is sometimes called before the register usage and sometimes afterwards } @@ -1093,7 +1088,6 @@ unit cgcpu; function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference; var tmpref : treference; - l : tasmlabel; begin Result:=ref; @@ -1702,8 +1696,7 @@ unit cgcpu; procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize; cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel); var - swapped , test_msb: boolean; - tmpreg : tregister; + swapped : boolean; i : byte; begin if a=0 then @@ -1856,7 +1849,7 @@ unit cgcpu; procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); var l : TAsmLabel; - tmpflags : TResFlags; + //tmpflags : TResFlags; i: Integer; hreg: TRegister; begin @@ -1889,8 +1882,8 @@ unit cgcpu; procedure tcgavr.a_adjust_sp(list : TAsmList; value : longint); - var - i : integer; + {var + i : integer; } begin case value of 0: @@ -2448,7 +2441,7 @@ unit cgcpu; var countreg,tmpreg,tmpreg2: tregister; srcref,dstref : treference; - copysize,countregsize : tcgsize; + countregsize : tcgsize; l : TAsmLabel; i : longint; SrcQuickRef, DestQuickRef : Boolean; @@ -2464,7 +2457,6 @@ unit cgcpu; dstref.base:=NR_R26; dstref.addressmode:=AM_POSTINCREMENT; - copysize:=OS_8; if len<256 then countregsize:=OS_8 else if len<65536 then diff --git a/avx512-0037785/compiler/avr/cpupara.pas b/avx512-0037785/compiler/avr/cpupara.pas index 597c493328..45d6cd1c19 100644 --- a/avx512-0037785/compiler/avr/cpupara.pas +++ b/avx512-0037785/compiler/avr/cpupara.pas @@ -201,7 +201,6 @@ unit cpupara; paracgsize : tcgsize; paralen : longint; i : integer; - firstparaloc: boolean; procedure assignintreg; begin @@ -300,7 +299,6 @@ unit cpupara; if paralen=0 then internalerror(200410311); {$endif EXTDEBUG} - firstparaloc:=true; if loc=LOC_REGISTER then begin { the lsb is located in the register with the lowest number, @@ -386,7 +384,6 @@ unit cpupara; inc(paraloc^.reference.offset,2); end; end; - firstparaloc:=false; end; end; curfloatreg:=nextfloatreg; @@ -400,7 +397,6 @@ unit cpupara; var cur_stack_offset: aword; curintreg, curfloatreg, curmmreg: tsuperregister; - retcgsize : tcgsize; begin init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset); diff --git a/avx512-0037785/compiler/avr/navradd.pas b/avx512-0037785/compiler/avr/navradd.pas index d83c2708dd..e704557887 100644 --- a/avx512-0037785/compiler/avr/navradd.pas +++ b/avx512-0037785/compiler/avr/navradd.pas @@ -33,11 +33,12 @@ interface private function GetResFlags(unsigned:Boolean):TResFlags; protected - function pass_1 : tnode;override; procedure second_cmpordinal;override; procedure second_cmpsmallset;override; procedure second_cmp64bit;override; procedure second_cmp; + public + function pass_1 : tnode;override; end; implementation diff --git a/avx512-0037785/compiler/avr/navrmat.pas b/avx512-0037785/compiler/avr/navrmat.pas index 67bf632fe6..751dfc8cef 100644 --- a/avx512-0037785/compiler/avr/navrmat.pas +++ b/avx512-0037785/compiler/avr/navrmat.pas @@ -59,7 +59,7 @@ implementation procedure tavrnotnode.second_boolean; var - tmpreg,lreg : tregister; + tmpreg : tregister; i : longint; falselabel,truelabel,skiplabel: TAsmLabel; begin diff --git a/avx512-0037785/compiler/avr/raavrgas.pas b/avx512-0037785/compiler/avr/raavrgas.pas index c5b1ae5bd7..48efcd3759 100644 --- a/avx512-0037785/compiler/avr/raavrgas.pas +++ b/avx512-0037785/compiler/avr/raavrgas.pas @@ -326,10 +326,8 @@ Unit raavrgas; var tempreg : tregister; - ireg : tsuperregister; hl : tasmlabel; ofs : longint; - registerset : tcpuregisterset; tempstr : string; tempsymtyp : tasmsymtype; Begin @@ -612,18 +610,16 @@ Unit raavrgas; function tavrattreader.is_asmopcode(const s: string):boolean; - +(* const { sorted by length so longer postfixes will match first } postfix2strsorted : array[1..19] of string[2] = ( 'EP','SB','BT','SH', 'IA','IB','DA','DB','FD','FA','ED','EA', 'B','D','E','P','T','H','S'); - +*) var - len, - j, - sufidx : longint; + j : longint; hs : string; maxlen : longint; icond : tasmcond; diff --git a/avx512-0037785/compiler/avr/rgcpu.pas b/avx512-0037785/compiler/avr/rgcpu.pas index 667d83325a..1eb0afa659 100644 --- a/avx512-0037785/compiler/avr/rgcpu.pas +++ b/avx512-0037785/compiler/avr/rgcpu.pas @@ -56,8 +56,8 @@ unit rgcpu; procedure trgcpu.add_constraints(reg:tregister); - var - supreg,i : Tsuperregister; + {var + supreg,i : Tsuperregister;} begin case getsubreg(reg) of { Let 64bit floats conflict with all odd float regs } @@ -76,8 +76,8 @@ unit rgcpu; { Let 64bit ints conflict with all odd int regs } R_SUBQ: begin - supreg:=getsupreg(reg); { + supreg:=getsupreg(reg); i:=RS_G1; while (i<=RS_I7) do begin @@ -95,7 +95,6 @@ unit rgcpu; helpins : tai; tmpref : treference; helplist : TAsmList; - hreg : tregister; begin if (abs(spilltemp.offset)>63) or (CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) then begin @@ -121,7 +120,6 @@ unit rgcpu; var tmpref : treference; helplist : TAsmList; - hreg : tregister; begin if (abs(spilltemp.offset)>63) or (CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) then begin @@ -185,8 +183,6 @@ unit rgcpu; function trgcpu.do_spill_replace(list:TAsmList;instr:tai_cpu_abstract_sym;orgreg:tsuperregister;const spilltemp:treference):boolean; - var - b : byte; begin result:=false; if not(spilltemp.offset in [0..63]) or (CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) then diff --git a/avx512-0037785/compiler/cfidwarf.pas b/avx512-0037785/compiler/cfidwarf.pas index 767e45f3fb..6d65387e51 100644 --- a/avx512-0037785/compiler/cfidwarf.pas +++ b/avx512-0037785/compiler/cfidwarf.pas @@ -435,7 +435,8 @@ implementation end else begin - tc:=tai_const.create_sym(cielabel); + { according to the dwarf (2 to 4) standard, this is an uword being always 32 bit unsigned } + tc:=tai_const.create_type_sym(aitconst_32bit,cielabel); { force label offset to secrel32 for windows systems } if (target_info.system in systems_windows+systems_wince) then tc.consttype:=aitconst_secrel32_symbol; diff --git a/avx512-0037785/compiler/dbgcodeview.pas b/avx512-0037785/compiler/dbgcodeview.pas index f2a3f6b6dd..814b645245 100644 --- a/avx512-0037785/compiler/dbgcodeview.pas +++ b/avx512-0037785/compiler/dbgcodeview.pas @@ -124,7 +124,7 @@ interface LF_PAD10 = $fa, LF_PAD11 = $fb, LF_PAD12 = $fc, - LF_PAD13 = $fc, + LF_PAD13 = $fd, LF_PAD14 = $fe, LF_PAD15 = $ff, diff --git a/avx512-0037785/compiler/dbgstabs.pas b/avx512-0037785/compiler/dbgstabs.pas index ef8a575475..8b26099a61 100644 --- a/avx512-0037785/compiler/dbgstabs.pas +++ b/avx512-0037785/compiler/dbgstabs.pas @@ -571,7 +571,7 @@ implementation just associated to pointer types } use_tag_prefix:=(def.typ in tagtypes) and ((def.typ<>stringdef) or - (tstringdef(tdef).stringtype in [st_shortstring,st_longstring])); + (tstringdef(def).stringtype in [st_shortstring,st_longstring])); end; diff --git a/avx512-0037785/compiler/fpcdefs.inc b/avx512-0037785/compiler/fpcdefs.inc index 6b762b1c50..59b4c1f240 100644 --- a/avx512-0037785/compiler/fpcdefs.inc +++ b/avx512-0037785/compiler/fpcdefs.inc @@ -31,6 +31,31 @@ {$define USEINLINE} {$endif EXTDEBUG} +{$ifdef DEBUG_ALL_OPT} + { for aopt unit } + {$define DEBUG_OPTALLOC} + {$define DEBUG_INSTRUCTIONREGISTERDEPENDENCIES} + {for CPU/aoptcpu unit } + {$define DEBUG_AOPTCPU} + {$define DEBUG_PREREGSCHEDULER (arm specific) } + { for aoptobj unit } + {$define DEBUG_AOPTOBJ} + {$define ALLOCREGDEBUG} + { for optconstprop unit } + {$define DEBUG_CONSTPROP} + { for optcse unit } + {$define CSEDEBUG} + { for optdeadstore unit } + {$define DEBUG_DEADSTORE} + { for optdfa unit } + {$define DEBUG_DFA} + { for optloop unit } + {$define DEBUG_OPTFORLOOP} + {$define DEBUG_OPTSTRENGTH} + { for optvirt unit } + {$define DEBUG_DEVIRT} +{$endif} + {$define USEEXCEPT} {$ifdef VER3_0} diff --git a/avx512-0037785/compiler/globtype.pas b/avx512-0037785/compiler/globtype.pas index 2e674ab459..c129d242b8 100644 --- a/avx512-0037785/compiler/globtype.pas +++ b/avx512-0037785/compiler/globtype.pas @@ -233,7 +233,9 @@ interface cs_assemble_on_target, { use a memory model which allows large data structures, e.g. > 2 GB static data on x86-64 targets this not supported on all OSes } - cs_large + cs_large, + { if applicable, the compiler generates an executable in uf2 format } + cs_generate_uf2 ); tglobalswitches = set of tglobalswitch; diff --git a/avx512-0037785/compiler/hlcgobj.pas b/avx512-0037785/compiler/hlcgobj.pas index 12404fa07f..fd425ffc56 100644 --- a/avx512-0037785/compiler/hlcgobj.pas +++ b/avx512-0037785/compiler/hlcgobj.pas @@ -4901,6 +4901,7 @@ implementation procedure thlcgobj.initialize_regvars(p: TObject; arg: pointer); var href : treference; + mmreg : tregister; begin if (tsym(p).typ=staticvarsym) and not(tstaticvarsym(p).noregvarinitneeded) then begin @@ -4922,12 +4923,18 @@ implementation tstaticvarsym(p).initialloc.register); end; LOC_CMMREGISTER : - { clear the whole register } - a_opmm_reg_reg(TAsmList(arg),OP_XOR,tstaticvarsym(p).vardef, - { as we pass shuffle=nil, we have to pass a full register } - newreg(R_MMREGISTER,getsupreg(tstaticvarsym(p).initialloc.register),R_SUBMMWHOLE), - newreg(R_MMREGISTER,getsupreg(tstaticvarsym(p).initialloc.register),R_SUBMMWHOLE), - nil); + begin +{$ifdef ARM} + { Do not pass d0 (which uses f0 and f1) for arm single type variable } + mmreg:=tstaticvarsym(p).initialloc.register; +{$else} + { clear the whole register } + mmreg:=newreg(R_MMREGISTER,getsupreg(tstaticvarsym(p).initialloc.register),R_SUBMMWHOLE); +{$endif} + a_opmm_reg_reg(TAsmList(arg),OP_XOR,tstaticvarsym(p).vardef, mmreg, mmreg, + { as we pass shuffle=nil, we have to pass a full register } + nil); + end; LOC_CFPUREGISTER : begin { initialize fpu regvar by loading from memory } diff --git a/avx512-0037785/compiler/i386/aoptcpu.pas b/avx512-0037785/compiler/i386/aoptcpu.pas index c6b667525e..fffa1a251d 100644 --- a/avx512-0037785/compiler/i386/aoptcpu.pas +++ b/avx512-0037785/compiler/i386/aoptcpu.pas @@ -137,6 +137,8 @@ unit aoptcpu; if InsContainsSegRef(taicpu(p)) then exit; case taicpu(p).opcode Of + A_ADD: + Result:=OptPass1ADD(p); A_AND: Result:=OptPass1And(p); A_IMUL: diff --git a/avx512-0037785/compiler/i8086/cpupara.pas b/avx512-0037785/compiler/i8086/cpupara.pas index db174e9ee4..628327db7e 100644 --- a/avx512-0037785/compiler/i8086/cpupara.pas +++ b/avx512-0037785/compiler/i8086/cpupara.pas @@ -101,8 +101,6 @@ unit cpupara; function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean; - var - size: longint; begin if handle_common_ret_in_param(def,pd,result) then exit; @@ -307,7 +305,6 @@ unit cpupara; var retcgsize : tcgsize; paraloc : pcgparalocation; - sym: tfieldvarsym; usedef: tdef; handled: boolean; begin diff --git a/avx512-0037785/compiler/i8086/n8086mem.pas b/avx512-0037785/compiler/i8086/n8086mem.pas index 8e45c511e2..2a9de1fe6b 100644 --- a/avx512-0037785/compiler/i8086/n8086mem.pas +++ b/avx512-0037785/compiler/i8086/n8086mem.pas @@ -36,9 +36,9 @@ interface protected procedure set_labelsym_resultdef; override; procedure set_absvarsym_resultdef; override; - procedure pass_generate_code;override; public get_offset_only: boolean; + procedure pass_generate_code;override; end; ti8086derefnode = class(tx86derefnode) diff --git a/avx512-0037785/compiler/i8086/n8086tcon.pas b/avx512-0037785/compiler/i8086/n8086tcon.pas index e8f5ceb834..663a0806fc 100644 --- a/avx512-0037785/compiler/i8086/n8086tcon.pas +++ b/avx512-0037785/compiler/i8086/n8086tcon.pas @@ -57,7 +57,6 @@ uses hp: tnode; srsym: tsym; pd: tprocdef; - resourcestrrec: trecorddef; begin { support word/smallint constants, initialized with Seg() } if (def.ordtype in [u16bit,s16bit]) and (node.nodetype=inlinen) and diff --git a/avx512-0037785/compiler/i8086/symcpu.pas b/avx512-0037785/compiler/i8086/symcpu.pas index c614b8bc4a..c7d9ae05bd 100644 --- a/avx512-0037785/compiler/i8086/symcpu.pas +++ b/avx512-0037785/compiler/i8086/symcpu.pas @@ -130,6 +130,7 @@ type - it has no 'near' or 'far' specifiers - it is compiled in a $F- state } function default_far:boolean; + protected procedure Setinterfacedef(AValue: boolean);override; public constructor create(level:byte;doregister:boolean);override; diff --git a/avx512-0037785/compiler/jvm/agjasmin.pas b/avx512-0037785/compiler/jvm/agjasmin.pas index 58ed55ac42..1dde2ce7f9 100644 --- a/avx512-0037785/compiler/jvm/agjasmin.pas +++ b/avx512-0037785/compiler/jvm/agjasmin.pas @@ -1126,9 +1126,6 @@ implementation function getopstr(const o:toper) : ansistring; - var - d: double; - s: single; begin case o.typ of top_reg: diff --git a/avx512-0037785/compiler/jvm/cpubase.pas b/avx512-0037785/compiler/jvm/cpubase.pas index d204cb6e92..5755bfda1b 100644 --- a/avx512-0037785/compiler/jvm/cpubase.pas +++ b/avx512-0037785/compiler/jvm/cpubase.pas @@ -302,11 +302,11 @@ uses regnumber_index : array[tregisterindex] of tregisterindex = ( {$i rjvmrni.inc} ); - +(* std_regname_index : array[tregisterindex] of tregisterindex = ( {$i rjvmsri.inc} ); - +*) function reg_cgsize(const reg: tregister): tcgsize; begin result:=OS_NO; diff --git a/avx512-0037785/compiler/jvm/dbgjasm.pas b/avx512-0037785/compiler/jvm/dbgjasm.pas index 7186661093..fa475ec777 100644 --- a/avx512-0037785/compiler/jvm/dbgjasm.pas +++ b/avx512-0037785/compiler/jvm/dbgjasm.pas @@ -105,7 +105,6 @@ implementation afterprocstartlabel : tasmlabel; hp, afterproccodestart : tai; - instrcount : longint; begin { insert debug information for local variables and parameters, but only for routines implemented in the Pascal code } @@ -121,7 +120,6 @@ implementation { set the start label for local variables after the first instruction, because javac's code completion support assumes that all info at bytecode position 0 is for parameters } - instrcount:=0; afterproccodestart:=def.procstarttai; while assigned(afterproccodestart.next) do begin diff --git a/avx512-0037785/compiler/jvm/hlcgcpu.pas b/avx512-0037785/compiler/jvm/hlcgcpu.pas index b9f4f5f8b1..7bf73b2e04 100644 --- a/avx512-0037785/compiler/jvm/hlcgcpu.pas +++ b/avx512-0037785/compiler/jvm/hlcgcpu.pas @@ -188,6 +188,8 @@ uses procedure gen_initialize_fields_code(list:TAsmList); procedure gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef); + + procedure g_copyvalueparas(p: TObject; arg: pointer); override; protected procedure a_load_const_stack_intern(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType; legalize_const: boolean); @@ -198,8 +200,6 @@ uses procedure allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference); procedure gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara); override; - procedure g_copyvalueparas(p: TObject; arg: pointer); override; - procedure inittempvariables(list:TAsmList);override; function g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara; override; diff --git a/avx512-0037785/compiler/jvm/njvminl.pas b/avx512-0037785/compiler/jvm/njvminl.pas index 34af3952a8..f1a9358f38 100644 --- a/avx512-0037785/compiler/jvm/njvminl.pas +++ b/avx512-0037785/compiler/jvm/njvminl.pas @@ -161,7 +161,7 @@ implementation function tjvminlinenode.first_copy: tnode; var ppn: tcallparanode; - arr, len, start, kind: tnode; + arr, len, start: tnode; eledef: tdef; counter, ndims: longint; finaltype: char; @@ -401,7 +401,6 @@ implementation lefttemp: ttempcreatenode; newblock: tblocknode; newstatement: tstatementnode; - primitive: boolean; begin { first parameter is the array, the rest are the dimensions } newparas:=tcallparanode(left).right; diff --git a/avx512-0037785/compiler/jvm/njvmmat.pas b/avx512-0037785/compiler/jvm/njvmmat.pas index 61fb0bf586..0e473bdfde 100644 --- a/avx512-0037785/compiler/jvm/njvmmat.pas +++ b/avx512-0037785/compiler/jvm/njvmmat.pas @@ -78,7 +78,6 @@ implementation var tmpreg: tregister; lab: tasmlabel; - ovloc: tlocation; op: topcg; isu32int: boolean; begin diff --git a/avx512-0037785/compiler/jvm/njvmmem.pas b/avx512-0037785/compiler/jvm/njvmmem.pas index 9c608746f6..d51d3b1d42 100644 --- a/avx512-0037785/compiler/jvm/njvmmem.pas +++ b/avx512-0037785/compiler/jvm/njvmmem.pas @@ -179,10 +179,7 @@ implementation function tjvmaddrnode.isdererence: boolean; - var - target: tnode; begin - target:=actualtargetnode(@left)^; result:= (left.nodetype=derefn); end; diff --git a/avx512-0037785/compiler/m68k/aoptcpu.pas b/avx512-0037785/compiler/m68k/aoptcpu.pas index 948bc28ff1..79b4331895 100644 --- a/avx512-0037785/compiler/m68k/aoptcpu.pas +++ b/avx512-0037785/compiler/m68k/aoptcpu.pas @@ -253,26 +253,30 @@ unit aoptcpu; opstr:=opname(p); case taicpu(p).oper[0]^.typ of top_reg: - begin - { move %reg0, %tmpreg; move %tmpreg, <ea> -> move %reg0, <ea> } - taicpu(p).loadOper(1,taicpu(next).oper[1]^); - asml.remove(next); - next.free; - result:=true; - { also remove leftover move %reg0, %reg0, which can occur as the result - of the previous optimization, if %reg0 and %tmpreg was different types - (addr vs. data), so these moves were left in by the cg } - if MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) then - begin - DebugMsg('Optimizer: '+opstr+' + '+opstr+' removed',p); - GetNextInstruction(p,next); - asml.remove(p); - p.free; - p:=next; - end - else - DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #1',p) - end; + { do not optimize away FPU to INT to FPU reg moves. These are used for + to-single-rounding on FPUs which have no FSMOVE/FDMOVE. (KB) } + if not ((taicpu(p).opcode = A_FMOVE) and + (getregtype(taicpu(p).oper[0]^.reg) <> getregtype(taicpu(p).oper[1]^.reg))) then + begin + { move %reg0, %tmpreg; move %tmpreg, <ea> -> move %reg0, <ea> } + taicpu(p).loadOper(1,taicpu(next).oper[1]^); + asml.remove(next); + next.free; + result:=true; + { also remove leftover move %reg0, %reg0, which can occur as the result + of the previous optimization, if %reg0 and %tmpreg was different types + (addr vs. data), so these moves were left in by the cg } + if MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) then + begin + DebugMsg('Optimizer: '+opstr+' + '+opstr+' removed',p); + GetNextInstruction(p,next); + asml.remove(p); + p.free; + p:=next; + end + else + DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #1',p) + end; top_const: begin // DebugMsg('Optimizer: '+opstr+' + '+opstr+' to '+opstr+' #2',p); diff --git a/avx512-0037785/compiler/m68k/cgcpu.pas b/avx512-0037785/compiler/m68k/cgcpu.pas index d46b5c4f07..be88900d21 100644 --- a/avx512-0037785/compiler/m68k/cgcpu.pas +++ b/avx512-0037785/compiler/m68k/cgcpu.pas @@ -1051,10 +1051,40 @@ unit cgcpu; procedure tcg68k.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); var instr : taicpu; + op: tasmop; + href: treference; + hreg: tregister; begin - instr:=taicpu.op_reg_reg(A_FMOVE,fpuregopsize,reg1,reg2); - add_move_instruction(instr); - list.concat(instr); + if fromsize > tosize then + begin + { we have to do a load-store through an intregister or the stack in this case, + which is probably the fastest way, and simpler than messing around with FPU control + words for one-off custom rounding (KB) } + case tosize of + OS_F32: + begin + //list.concat(tai_comment.create(strpnew('a_loadfpu_reg_reg rounding via intreg'))); + hreg := getintregister(list,OS_32); + list.concat(taicpu.op_reg_reg(A_FMOVE, tcgsize2opsize[tosize], reg1, hreg)); + list.concat(taicpu.op_reg_reg(A_FMOVE, tcgsize2opsize[tosize], hreg, reg2)); + end; + else + begin + //list.concat(tai_comment.create(strpnew('a_loadfpu_reg_reg rounding via stack'))); + reference_reset_base(href, NR_STACK_POINTER_REG, 0, ctempposinvalid, 0, []); + href.direction:=dir_dec; + list.concat(taicpu.op_reg_ref(A_FMOVE, tcgsize2opsize[tosize], reg1, href)); + href.direction:=dir_inc; + list.concat(taicpu.op_ref_reg(A_FMOVE, tcgsize2opsize[tosize], href, reg2)); + end; + end; + end + else + begin + instr:=taicpu.op_reg_reg(A_FMOVE,fpuregopsize,reg1,reg2); + add_move_instruction(instr); + list.concat(instr); + end; end; @@ -1067,6 +1097,8 @@ unit cgcpu; href := ref; fixref(list,href,current_settings.fputype = fpu_coldfire); list.concat(taicpu.op_ref_reg(A_FMOVE,opsize,href,reg)); + if fromsize > tosize then + a_load_reg_reg(list,fromsize,tosize,reg,reg); end; procedure tcg68k.a_loadfpu_reg_ref(list: TAsmList; fromsize,tosize: tcgsize; reg: tregister; const ref: treference); diff --git a/avx512-0037785/compiler/msg/errorct.msg b/avx512-0037785/compiler/msg/errorct.msg index 3aea8fafb2..1275367752 100644 --- a/avx512-0037785/compiler/msg/errorct.msg +++ b/avx512-0037785/compiler/msg/errorct.msg @@ -1,6 +1,6 @@ # # This file is part of the Free Pascal Compiler -# Copyright (c) 1993-2020 by the Free Pascal Development team +# Copyright (c) 1993-2021 by the Free Pascal Development team # # Catalan Language File for Free Pascal # @@ -2103,7 +2103,7 @@ option_code_page_not_available=11039_E_La pgina del codi no est disponible # option_logo=11023_[ Free Pascal Compiler versi $FPCFULLVERSION [$FPCDATE] per $FPCCPU -Copyright (c) 1993-2020 per Florian Klaempfl and others +Copyright (c) 1993-2021 per Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errord.msg b/avx512-0037785/compiler/msg/errord.msg index 59e7afc577..d8e37df549 100644 --- a/avx512-0037785/compiler/msg/errord.msg +++ b/avx512-0037785/compiler/msg/errord.msg @@ -6,7 +6,7 @@ # Based on errore.msg of SVN revision 45316 # # This file is part of the Free Pascal Compiler -# Copyright (c) 1998-2020 by the Free Pascal Development team +# Copyright (c) 1998-2021 by the Free Pascal Development team # # See the file COPYING.v2, included in this distribution, # for details about the copyright. @@ -3585,7 +3585,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Ungltiger Wert fr die Umgebu % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_Sie mssen beim Ziel EABIHF ABI einen der FPU Typen VFPV2, VFPV3 oder VFPV3_D16 verwenden +option_illegal_fpu_eabihf=11052_E_Sie mssen beim Ziel EABIHF ABI einen der VFP FPU-Typen verwenden % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_Das ausgewhlte Debugformat wird auf dem aktuellen Ziel nicht untersttzt. Die aktuelle Einstellung wird beibehalten % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3784,7 +3784,7 @@ package_u_ppl_filename=13029_U_PPL Dateiname $1 # option_logo=11023_[ Free Pascal Compiler Version $FPCFULLVERSION [$FPCDATE] fr $FPCTARGET -Copyright (c) 1993-2020 Florian Klmpfl und andere +Copyright (c) 1993-2021 Florian Klmpfl und andere ] # diff --git a/avx512-0037785/compiler/msg/errorda.msg b/avx512-0037785/compiler/msg/errorda.msg index b4b0ab21f2..f610f8fabf 100644 --- a/avx512-0037785/compiler/msg/errorda.msg +++ b/avx512-0037785/compiler/msg/errorda.msg @@ -3438,7 +3438,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3535,7 +3535,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] til $FPCTARGET -Copyright (c) 1993-2020 Florian Klaempfl and others +Copyright (c) 1993-2021 Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errordu.msg b/avx512-0037785/compiler/msg/errordu.msg index e03e4ea1ec..7a02a6d617 100644 --- a/avx512-0037785/compiler/msg/errordu.msg +++ b/avx512-0037785/compiler/msg/errordu.msg @@ -6,7 +6,7 @@ # Based on errore.msg of SVN revision 45316 # # This file is part of the Free Pascal Compiler -# Copyright (c) 1998-2020 by the Free Pascal Development team +# Copyright (c) 1998-2021 by the Free Pascal Development team # # See the file COPYING.v2, included in this distribution, # for details about the copyright. @@ -3585,7 +3585,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Ungültiger Wert für die Umge % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_Sie müssen beim Ziel EABIHF ABI einen der FPU Typen VFPV2, VFPV3 oder VFPV3_D16 verwenden +option_illegal_fpu_eabihf=11052_E_Sie müssen beim Ziel EABIHF ABI einen der VFP FPU-Typen verwenden % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_Das ausgewählte Debugformat wird auf dem aktuellen Ziel nicht unterstützt. Die aktuelle Einstellung wird beibehalten % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3784,7 +3784,7 @@ package_u_ppl_filename=13029_U_PPL Dateiname $1 # option_logo=11023_[ Free Pascal Compiler Version $FPCFULLVERSION [$FPCDATE] für $FPCTARGET -Copyright (c) 1993-2020 Florian Klämpfl und andere +Copyright (c) 1993-2021 Florian Klämpfl und andere ] # diff --git a/avx512-0037785/compiler/msg/errore.msg b/avx512-0037785/compiler/msg/errore.msg index 9874f1e40c..78d0f1bf78 100644 --- a/avx512-0037785/compiler/msg/errore.msg +++ b/avx512-0037785/compiler/msg/errore.msg @@ -1555,7 +1555,7 @@ parser_w_ptr_type_ignored=03338_W_Pointer type "$1" ignored % The specified pointer type modifier is ignored, because it is not supported on % the current platform. This happens, for example, when a far pointer is % declared on a non-x86 platform. -parser_e_global_generic_references_static=03339_E_Global Generic template references static symtable +parser_e_global_generic_references_static=03339_E_Generic template in interface section references symbol in implementation section % A generic declared in the interface section of a unit must not reference symbols that belong % solely to the implementation section of that unit. parser_u_already_compiled=03340_UL_Unit $1 has been already compiled meanwhile. @@ -1622,6 +1622,8 @@ parser_e_location_regpair_only_data=03358_E_Only data registers are supported fo % AmigaOS/MorphOS syscall specific: for 64bit register pairs, only data registers are supported parser_e_location_regpair_only_consecutive=03359_E_Only consecutive registers are supported for explicit location register pairs % MorphOS syscall specific: only consecutive (f.e.: d1-d2) registers are supported for 64bit register pairs +parser_e_constructurs_cannot_take_type_parameters=03360_E_Constructors cannot take type parameters +% The use of type parameters in constructors is not allowed. % % \end{description} % @@ -3556,7 +3558,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3755,7 +3757,7 @@ package_u_ppl_filename=13029_U_PPL filename $1 # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # @@ -4348,6 +4350,7 @@ F*2Xp<x>_First search for the compiler binary in the directory <x> **2Xs_Strip all symbols from executable **2XS_Try to link units statically (default, defines FPC_LINK_STATIC) **2Xt_Link with static libraries (-static is passed to linker) +**2Xu_Generate executable in UF2 format (embedded targets only) **2Xv_Generate table for Virtual Entry calls **2XV_Use VLink as external linker (default on Amiga, MorphOS) **2XX_Try to smartlink units (defines FPC_LINK_SMART) diff --git a/avx512-0037785/compiler/msg/errores.msg b/avx512-0037785/compiler/msg/errores.msg index 93e86399f3..e7eff83ce7 100644 --- a/avx512-0037785/compiler/msg/errores.msg +++ b/avx512-0037785/compiler/msg/errores.msg @@ -3380,7 +3380,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3477,7 +3477,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorf.msg b/avx512-0037785/compiler/msg/errorf.msg index 1174238b5d..3ca9d2f308 100644 --- a/avx512-0037785/compiler/msg/errorf.msg +++ b/avx512-0037785/compiler/msg/errorf.msg @@ -1715,7 +1715,7 @@ option_asm_forced=11022_W_"$1" assembler use forced # option_logo=11023_[ Compilateur Free Pascal version $FPCFULLVERSION [$FPCDATE] pour $FPCTARGET -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorfi.msg b/avx512-0037785/compiler/msg/errorfi.msg index 1dadd321c4..a1c91eadc2 100644 --- a/avx512-0037785/compiler/msg/errorfi.msg +++ b/avx512-0037785/compiler/msg/errorfi.msg @@ -3403,7 +3403,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3499,7 +3499,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # Logo (option -l) # option_logo=11023_[ Compilateur Free Pascal version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020, Florian Klaempfl and others] +Copyright (c) 1993-2021, Florian Klaempfl and others] # # Info (option -i) # diff --git a/avx512-0037785/compiler/msg/errorhe.msg b/avx512-0037785/compiler/msg/errorhe.msg index 524621bfd8..b9ef626478 100644 --- a/avx512-0037785/compiler/msg/errorhe.msg +++ b/avx512-0037785/compiler/msg/errorhe.msg @@ -2407,7 +2407,7 @@ option_confict_asm_debug=11041_W_ "$1" # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorheu.msg b/avx512-0037785/compiler/msg/errorheu.msg index 04b2db1fac..a9548f08fa 100644 --- a/avx512-0037785/compiler/msg/errorheu.msg +++ b/avx512-0037785/compiler/msg/errorheu.msg @@ -3399,7 +3399,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3496,7 +3496,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorid.msg b/avx512-0037785/compiler/msg/errorid.msg index a0f29b8484..9c6d0ecda7 100644 --- a/avx512-0037785/compiler/msg/errorid.msg +++ b/avx512-0037785/compiler/msg/errorid.msg @@ -3407,7 +3407,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3504,7 +3504,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler versi $FPCFULLVERSION [$FPCDATE] untuk $FPCCPU -Hak Cipta (c) 1993-2020 oleh Florian Klaempfl and others +Hak Cipta (c) 1993-2021 oleh Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/erroriu.msg b/avx512-0037785/compiler/msg/erroriu.msg index 22c8be009e..127634d57d 100644 --- a/avx512-0037785/compiler/msg/erroriu.msg +++ b/avx512-0037785/compiler/msg/erroriu.msg @@ -2693,7 +2693,7 @@ wpo_cant_create_feedback_file=12019_E_Impossibile creare il file di feedback "$1 # option_logo=11023_[ Compilatore Free Pascal, versione $FPCFULLVERSION [$FPCDATE] per $FPCCPU -Copyright (c) 1993-2020 di Florian Klaempfl and others +Copyright (c) 1993-2021 di Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorn.msg b/avx512-0037785/compiler/msg/errorn.msg index 4f7fc19e20..25140d19b4 100644 --- a/avx512-0037785/compiler/msg/errorn.msg +++ b/avx512-0037785/compiler/msg/errorn.msg @@ -3388,7 +3388,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3485,7 +3485,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler versie $FPCFULLVERSION [$FPCDATE] voor $FPCTARGET -Copyright (c) 1993-2020 door Florian Klaempfl en anderen +Copyright (c) 1993-2021 door Florian Klaempfl en anderen ] # # Info (option -i) diff --git a/avx512-0037785/compiler/msg/errorpl.msg b/avx512-0037785/compiler/msg/errorpl.msg index 6db59ac21e..5270079c39 100644 --- a/avx512-0037785/compiler/msg/errorpl.msg +++ b/avx512-0037785/compiler/msg/errorpl.msg @@ -2119,7 +2119,7 @@ option_code_page_not_available=11039_E_Nieznana strona kodowa # option_logo=11023_[ Free Pascal Compiler wersja $FPCFULLVERSION [$FPCDATE] dla $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorpli.msg b/avx512-0037785/compiler/msg/errorpli.msg index fad211bef8..a306a6f1b8 100644 --- a/avx512-0037785/compiler/msg/errorpli.msg +++ b/avx512-0037785/compiler/msg/errorpli.msg @@ -2119,7 +2119,7 @@ option_code_page_not_available=11039_E_Nieznana strona kodowa # option_logo=11023_[ Free Pascal Compiler wersja $FPCFULLVERSION [$FPCDATE] dla $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorpt.msg b/avx512-0037785/compiler/msg/errorpt.msg index 8703d4fd8e..e01dfef32b 100644 --- a/avx512-0037785/compiler/msg/errorpt.msg +++ b/avx512-0037785/compiler/msg/errorpt.msg @@ -3086,7 +3086,7 @@ wpo_cant_create_feedback_file=12019_E_Impossvel criar arquivo retorno otimiza # option_logo=11023_[ Compilador Free Pascal verso $FPCFULLVERSION [$FPCDATE] para $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorptu.msg b/avx512-0037785/compiler/msg/errorptu.msg index 6ae762e814..4bbed9672c 100644 --- a/avx512-0037785/compiler/msg/errorptu.msg +++ b/avx512-0037785/compiler/msg/errorptu.msg @@ -3417,7 +3417,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3514,7 +3514,7 @@ wpo_cant_create_feedback_file=12019_E_Impossível criar arquivo retorno otimiza # option_logo=11023_[ Compilador Free Pascal versão $FPCFULLVERSION [$FPCDATE] para $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorr.msg b/avx512-0037785/compiler/msg/errorr.msg index de376fdde6..b34a0342fe 100644 --- a/avx512-0037785/compiler/msg/errorr.msg +++ b/avx512-0037785/compiler/msg/errorr.msg @@ -2506,7 +2506,7 @@ wpo_cant_create_feedback_file=12019_E_ ᮧ 䠩 ⭮ 裡 "$1" # option_logo=11023_[ Free Pascal ᨨ $FPCFULLVERSION [$FPCDATE] $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorru.msg b/avx512-0037785/compiler/msg/errorru.msg index 1f39e64e7b..77be2cfe0c 100644 --- a/avx512-0037785/compiler/msg/errorru.msg +++ b/avx512-0037785/compiler/msg/errorru.msg @@ -3292,7 +3292,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3387,7 +3387,7 @@ wpo_cant_create_feedback_file=12019_E_Невозможно создать фай # option_logo=11023_[ Компилятор Free Pascal версии $FPCFULLVERSION [$FPCDATE] для $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msg/errorues.msg b/avx512-0037785/compiler/msg/errorues.msg index 5777a05d13..2398ea14dd 100644 --- a/avx512-0037785/compiler/msg/errorues.msg +++ b/avx512-0037785/compiler/msg/errorues.msg @@ -3374,7 +3374,7 @@ option_invalid_iphoneos_deployment_target=11051_E_Invalid value for IPHONEOS_DEP % XY.Z or XY.Z.AB with X, Y,Z , A and B all digits from 0-9. % In case of iOS, it has to be X.Z.A, where X, Z and A can all be either 1 or 2 % digits from 0-9. -option_illegal_fpu_eabihf=11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when using the EABIHF ABI target +option_illegal_fpu_eabihf=11052_E_You must use one of the VFP FPU types when using the EABIHF ABI target % The EABIHF (VFP hardfloat) ABI target can only be used with VFP FPUs. option_w_unsupported_debug_format=11053_W_The selected debug format is not supported on the current target, not changing the current setting % Not all targets support all debug formats (in particular, Stabs is not supported on 64 bit targets). @@ -3471,7 +3471,7 @@ wpo_cant_create_feedback_file=12019_E_Cannot create specified whole program opti # option_logo=11023_[ Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPCCPU -Copyright (c) 1993-2020 by Florian Klaempfl and others +Copyright (c) 1993-2021 by Florian Klaempfl and others ] # diff --git a/avx512-0037785/compiler/msgidx.inc b/avx512-0037785/compiler/msgidx.inc index e7232b2c39..dd0f203213 100644 --- a/avx512-0037785/compiler/msgidx.inc +++ b/avx512-0037785/compiler/msgidx.inc @@ -471,6 +471,7 @@ const parser_e_location_size_too_large=03357; parser_e_location_regpair_only_data=03358; parser_e_location_regpair_only_consecutive=03359; + parser_e_constructurs_cannot_take_type_parameters=03360; type_e_mismatch=04000; type_e_incompatible_types=04001; type_e_not_equal_types=04002; @@ -1136,9 +1137,9 @@ const option_info=11024; option_help_pages=11025; - MsgTxtSize = 86940; + MsgTxtSize = 87070; MsgIdxMax : array[1..20] of longint=( - 28,107,360,130,99,63,146,36,223,68, + 28,107,361,130,99,63,146,36,223,68, 63,20,30,1,1,1,1,1,1,1 ); diff --git a/avx512-0037785/compiler/msgtxt.inc b/avx512-0037785/compiler/msgtxt.inc index f26b6e9110..7331a50698 100644 --- a/avx512-0037785/compiler/msgtxt.inc +++ b/avx512-0037785/compiler/msgtxt.inc @@ -560,862 +560,865 @@ const msgtxt : array[0..000362,1..240] of char=( '03337_E_Default values can only be specified for value, const and',' co'+ 'nstref parameters'#000+ '03338_W_Pointer type "$1" ignored'#000+ - '03339_E_Global Generic template references static symtable'#000+ + '03339_E_Generic template in interface section references symbol in imp'+ + 'lementation section'#000+ '03340_UL_Unit $1 has been already compiled meanwhile.'#000+ - '03341_E_Explicit implementation of methods for specializations of gene'+ - 'ri','cs is not allowed'#000+ + '03341_E_Explicit implementation of method','s for specializations of ge'+ + 'nerics is not allowed'#000+ '03342_E_Generic methods are not allowed in interfaces'#000+ '03343_E_Generic methods can not be virtual'#000+ '03344_E_Dynamic packages not supported for target OS'#000+ - '03345_E_The HardFloat directive cannot be used if soft float code is g'+ - 'en','erated or fpu emulation is turned on'#000+ + '03345_E_The HardFloat directive cannot be',' used if soft float code is'+ + ' generated or fpu emulation is turned on'#000+ '03346_E_Index $1 is not a valid internal function index'#000+ '03347_W_Operator overload hidden by internal operator: "$1" $2 "$3"'#000+ - '03348_E_Thread variables inside classes or records must be class varia'+ - 'bles'#000+ - '0334','9_E_Only static methods and static variables can be referenced t'+ - 'hrough an object type'#000+ + '03348_E_Thread variables inside classes or recor','ds must be class var'+ + 'iables'#000+ + '03349_E_Only static methods and static variables can be referenced thr'+ + 'ough an object type'#000+ '03350_E_Cannot redeclare C-style variadic function "$1" as external on'+ - ' this platform; make its first declaration already external'#000+ - '03351_E_Unbound custom a','ttribute: "$1".'#000+ + ' this platform; make its first declaration already ex','ternal'#000+ + '03351_E_Unbound custom attribute: "$1".'#000+ '03352_E_Enumeration symbols can only have values in the range of -2^31'+ ' to 2^31-1'#000+ '03353_W_Enumeration symbols can only have values in the range of -2^31'+ ' to 2^31-1'#000+ - '03354_E_Implementing a method for type "$1" declared in anothe','r unit'+ + '03354_E_Implementing a method f','or type "$1" declared in another unit'+ #000+ '03355_E_Generic constraint not allowed here'#000+ '03356_E_Explicit location is too small for parameter'#000+ '03357_E_Explicit location size is larger than required by parameter'#000+ - '03358_E_Only data registers are supported for explicit location regi','s'+ - 'ter pairs'#000+ + '03358_E_Only data registers are suppo','rted for explicit location regi'+ + 'ster pairs'#000+ '03359_E_Only consecutive registers are supported for explicit location'+ ' register pairs'#000+ + '03360_E_Constructors cannot take type parameters'#000+ '04000_E_Type mismatch'#000+ - '04001_E_Incompatible types: got "$1" expected "$2"'#000+ + '04001_E_Incompatible types: got "$1" expe','cted "$2"'#000+ '04002_E_Type mismatch between "$1" and "$2"'#000+ - '04003_E_Type identifier ex','pected'#000+ + '04003_E_Type identifier expected'#000+ '04004_E_Variable identifier expected'#000+ '04005_E_Integer expression expected, but got "$1"'#000+ '04006_E_Boolean expression expected, but got "$1"'#000+ - '04007_E_Ordinal expression expected'#000+ + '04007_E_Ordinal ','expression expected'#000+ '04008_E_Pointer type expected, but got "$1"'#000+ - '04009_E_Class ty','pe expected, but got "$1"'#000+ + '04009_E_Class type expected, but got "$1"'#000+ '04011_E_Can'#039't evaluate constant expression'#000+ '04012_E_Set elements are not compatible'#000+ '04013_E_Operation not implemented for sets'#000+ - '04014_W_Automatic type conversion from floating type to COMP which is '+ - 'an integer type'#000+ - '04','015_H_Use DIV instead to get an integer result'#000+ + '04014_W_','Automatic type conversion from floating type to COMP which i'+ + 's an integer type'#000+ + '04015_H_Use DIV instead to get an integer result'#000+ '04016_E_String types have to match exactly in $V+ mode'#000+ - '04017_E_Succ or Pred on enums with assignments not possible'#000+ + '04017_E_Succ or Pred on enums with assignments not possibl','e'#000+ '04018_E_Can'#039't read or write variables of this type'#000+ - '04019_E_Can'#039't use readln or',' writeln on typed file'#000+ + '04019_E_Can'#039't use readln or writeln on typed file'#000+ '04020_E_Can'#039't use read or write on untyped file.'#000+ '04021_E_Type conflict between set elements'#000+ - '04022_W_lo/hi(dword/qword) returns the upper/lower word/dword'#000+ + '04022_W_lo/hi(dword/qword) returns the upper/','lower word/dword'#000+ '04023_E_Integer or real expression expected'#000+ - '04024_E_Wrong type ','"$1" in array constructor'#000+ + '04024_E_Wrong type "$1" in array constructor'#000+ '04025_E_Incompatible type for arg no. $1: Got "$2", expected "$3"'#000+ - '04026_E_Method (variable) and Procedure (variable) are not compatible'#000+ + '04026_E_Method (variable) and Procedure (variable) are not compatibl','e'+ + #000+ '04027_E_Illegal constant passed to internal math function'#000+ - '04028_E_Can'#039't take t','he address of constant expressions'#000+ + '04028_E_Can'#039't take the address of constant expressions'#000+ '04029_E_Argument cannot be assigned to'#000+ '04030_E_Can'#039't assign local procedure/function to procedure variabl'+ 'e'#000+ - '04031_E_Can'#039't assign values to an address'#000+ + '04031_E_Can'#039't assi','gn values to an address'#000+ '04032_E_Can'#039't assign values to const variable'#000+ - '04033_E_Ar','ray type required'#000+ + '04033_E_Array type required'#000+ '04034_E_Interface type expected, but got "$1"'#000+ '04035_H_Mixing signed expressions and longwords gives a 64bit result'#000+ - '04036_W_Mixing signed expressions and cardinals here may cause a range'+ - ' check error'#000+ - '04037_E_Typecast has dif','ferent size ($1 -> $2) in assignment'#000+ + '04036_W_Mixing signed expre','ssions and cardinals here may cause a ran'+ + 'ge check error'#000+ + '04037_E_Typecast has different size ($1 -> $2) in assignment'#000+ '04038_E_Enums with assignments cannot be used as array index'#000+ '04039_E_Class or Object types "$1" and "$2" are not related'#000+ - '04040_W_Class types "$1" and "$2" are not related'#000+ - '04041_E_Class or interface type ','expected, but got "$1"'#000+ + '04','040_W_Class types "$1" and "$2" are not related'#000+ + '04041_E_Class or interface type expected, but got "$1"'#000+ '04042_E_Type "$1" is not completely defined'#000+ '04043_W_String literal has more characters than short string length'#000+ - '04044_W_Comparison might be always false due to range of constant and '+ - 'expression'#000+ - '04045_W_Comparison might',' be always true due to range of constant and'+ - ' expression'#000+ + '04044_W_Comparison might ','be always false due to range of constant an'+ + 'd expression'#000+ + '04045_W_Comparison might be always true due to range of constant and e'+ + 'xpression'#000+ '04046_W_Constructing a class "$1" with abstract method "$2"'#000+ - '04047_H_The left operand of the IN operator should be byte sized'#000+ - '04048_W_Type size mismatch, possible loss of data / range c','heck erro'+ - 'r'#000+ + '04047_H_The left operand of the IN operator ','should be byte sized'#000+ + '04048_W_Type size mismatch, possible loss of data / range check error'#000+ '04049_H_Type size mismatch, possible loss of data / range check error'#000+ '04050_E_The address of an abstract method cannot be taken'#000+ - '04051_E_Assignments to formal parameters and open arrays are not possi'+ - 'ble'#000+ - '04052_E_Constant Expression',' expected'#000+ + '04051_E_Assignments t','o formal parameters and open arrays are not pos'+ + 'sible'#000+ + '04052_E_Constant Expression expected'#000+ '04053_E_Operation "$1" not supported for types "$2" and "$3"'#000+ '04054_E_Illegal type conversion: "$1" to "$2"'#000+ - '04055_H_Conversion between ordinals and pointers is not portable'#000+ - '04056_W_Conversion between ordinals and pointers is not po','rtable'#000+ + '04055_H_Conversion between ordinals and poi','nters is not portable'#000+ + '04056_W_Conversion between ordinals and pointers is not portable'#000+ '04057_E_Can'#039't determine which overloaded function to call'#000+ '04058_E_Illegal counter variable'#000+ - '04059_W_Converting constant real value to double for C variable argume'+ - 'nt, add explicit typecast to prevent this.'#000+ - '04060_E_Class or COM interfac','e type expected, but got "$1"'#000+ + '04059_W_Converting constant real value to double for C variabl','e argu'+ + 'ment, add explicit typecast to prevent this.'#000+ + '04060_E_Class or COM interface type expected, but got "$1"'#000+ '04061_E_Constant packed arrays are not yet supported'#000+ '04062_E_Incompatible type for arg no. $1: Got "$2" expected "(Bit)Pack'+ - 'ed Array"'#000+ + 'ed Arra','y"'#000+ '04063_E_Incompatible type for arg no. $1: Got "$2" expected "(not pack'+ - 'ed) Arr','ay"'#000+ + 'ed) Array"'#000+ '04064_E_Elements of packed arrays cannot be of a type which need to be'+ ' initialised'#000+ '04065_E_Constant packed records and objects are not yet supported'#000+ - '04066_W_Arithmetic "$1" on untyped pointer is unportable to {$T+}, sug'+ - 'gest typecast'#000+ - '040','76_E_Can'#039't take address of a subroutine marked as local'#000+ + '04066_W','_Arithmetic "$1" on untyped pointer is unportable to {$T+}, s'+ + 'uggest typecast'#000+ + '04076_E_Can'#039't take address of a subroutine marked as local'#000+ '04077_E_Can'#039't export subroutine marked as local from a unit'#000+ '04078_E_Type is not automatable: "$1"'#000+ - '04079_H_Converting the operands to "$1" before doing the add could pre'+ - 'vent overflow er','rors.'#000+ + '04079_','H_Converting the operands to "$1" before doing the add could p'+ + 'revent overflow errors.'#000+ '04080_H_Converting the operands to "$1" before doing the subtract coul'+ 'd prevent overflow errors.'#000+ - '04081_H_Converting the operands to "$1" before doing the multiply coul'+ - 'd prevent overflow errors.'#000+ - '04082_W_Converting pointers to signed in','tegers may result in wrong c'+ - 'omparison results and range errors, use an unsigned type instead.'#000+ + '04081_H_Converting the operands to "$1" before doing the ','multiply co'+ + 'uld prevent overflow errors.'#000+ + '04082_W_Converting pointers to signed integers may result in wrong com'+ + 'parison results and range errors, use an unsigned type instead.'#000+ '04083_E_Interface type $1 has no valid GUID'#000+ - '04084_E_Invalid selector name "$1"'#000+ + '04084_E_Invalid select','or name "$1"'#000+ '04085_E_Expected Objective-C method, but got $1'#000+ - '04086_E_Expected Ob','jective-C method or constant method name'#000+ + '04086_E_Expected Objective-C method or constant method name'#000+ '04087_E_No type info available for this type'#000+ '04088_E_Ordinal or string expression expected'#000+ - '04089_E_String expression expected'#000+ + '04089_E_String expression ex','pected'#000+ '04090_W_Converting 0 to NIL'#000+ - '04091_E_Objective-C protocol type expected, b','ut got "$1"'#000+ + '04091_E_Objective-C protocol type expected, but got "$1"'#000+ '04092_E_The type "$1" is not supported for interaction with the Object'+ 'ive-C and the blocks runtime.'#000+ - '04093_E_Class or objcclass type expected, but got "$1"'#000+ + '04093_E_Class or objcclass type expected, but go','t "$1"'#000+ '04094_E_Objcclass type expected'#000+ - '04095_W_Coerced univ parameter type in pr','ocedural variable may cause'+ - ' crash or memory corruption: $1 to $2'#000+ + '04095_W_Coerced univ parameter type in procedural variable may cause c'+ + 'rash or memory corruption: $1 to $2'#000+ '04096_E_Type parameters of specializations of generics cannot referenc'+ - 'e the currently specialized type'#000+ + 'e the currently specializ','ed type'#000+ '04097_E_Type parameters are not allowed on non-generic class/record/ob'+ - 'je','ct procedure or function'#000+ + 'ject procedure or function'#000+ '04098_E_Generic declaration of "$1" differs from previous declaration'#000+ '04099_E_Helper type expected'#000+ '04100_E_Record type expected'#000+ - '04101_E_Derived class helper must extend a subclass of "$1" or the cla'+ - 'ss itself'#000+ - '04102_E','_Derived record or type helper must extend "$1"'#000+ + '04101_E','_Derived class helper must extend a subclass of "$1" or the c'+ + 'lass itself'#000+ + '04102_E_Derived record or type helper must extend "$1"'#000+ '04103_E_Invalid assignment, procedures return no value'#000+ - '04104_W_Implicit string type conversion from "$1" to "$2"'#000+ + '04104_W_Implicit string type conversion from "$1" to "$2"',#000+ '04105_W_Implicit string type conversion with potential data loss from '+ - '"$1" to "','$2"'#000+ + '"$1" to "$2"'#000+ '04106_-W_Explicit string typecast from "$1" to "$2"'#000+ '04107_-W_Explicit string typecast with potential data loss from "$1" t'+ 'o "$2"'#000+ - '04108_W_Unicode constant cast with potential data loss'#000+ - '04109_E_Range check error while evaluating constants',' ($1 must be bet'+ - 'ween $2 and $3)'#000+ + '04108_W_Unicode constant ca','st with potential data loss'#000+ + '04109_E_Range check error while evaluating constants ($1 must be betwe'+ + 'en $2 and $3)'#000+ '04110_W_Range check error while evaluating constants ($1 must be betwe'+ 'en $2 and $3)'#000+ - '04111_E_This type is not supported for the Default() intrinsic'#000+ + '04111_E_This type is not supported for the D','efault() intrinsic'#000+ '04112_E_JVM virtual class methods cannot be static'#000+ - '04113_E_Fi','nal (class) fields can only be assigned in their class'#039+ - ' (class) constructor'#000+ + '04113_E_Final (class) fields can only be assigned in their class'#039' '+ + '(class) constructor'#000+ '04114_E_It is not possible to typecast untyped parameters on managed p'+ - 'latforms, simply assign a value to them instead.'#000+ - '04115_E_The assignment side of an expression ','cannot be typecasted to'+ - ' a supertype on managed platforms'#000+ + 'latforms, simp','ly assign a value to them instead.'#000+ + '04115_E_The assignment side of an expression cannot be typecasted to a'+ + ' supertype on managed platforms'#000+ '04116_-W_The interface method "$1" raises the visibility of "$2" to pu'+ - 'blic when accessed via an interface instance'#000+ - '04117_E_The interface method "$1" has a higher visibility (public) t','h'+ - 'an "$2"'#000+ + 'blic when accessed via an interfa','ce instance'#000+ + '04117_E_The interface method "$1" has a higher visibility (public) tha'+ + 'n "$2"'#000+ '04118_E_TYPEOF can only be used on object types with VMT'#000+ '04119_E_It is not possible to define a default value for a parameter o'+ 'f type "$1"'#000+ - '04120_E_Type "$1" cannot be extended by a type helper'#000+ - '04121_E_Procedure or function must be ','far in order to allow taking i'+ - 'ts address: "$1"'#000+ + '04120_E_Type',' "$1" cannot be extended by a type helper'#000+ + '04121_E_Procedure or function must be far in order to allow taking its'+ + ' address: "$1"'#000+ '04122_W_Creating an instance of abstract class "$1"'#000+ - '04123_E_Subroutine references cannot be declared as "of object" or "is'+ - ' nested", they can always refer to any kind of subroutine'#000+ - '04124_E_Proce','dure variables in that memory model do not store segmen'+ - 't information'#000+ + '04123_E_Subroutine references cannot be declared as "of objec','t" or "'+ + 'is nested", they can always refer to any kind of subroutine'#000+ + '04124_E_Procedure variables in that memory model do not store segment '+ + 'information'#000+ '04125_W_The first value of a set constructur range is greater then the'+ - ' second value, so the range describes an empty set.'#000+ - '04126_E_C block reference must use CDECL or MWPAS','CAL calling convent'+ - 'ion.'#000+ + ' second value, so the',' range describes an empty set.'#000+ + '04126_E_C block reference must use CDECL or MWPASCAL calling conventio'+ + 'n.'#000+ '04127_E_The interface type of the forward declaration and the declared'+ ' interface type do not match for interface $1'#000+ - '04128_E_Type not allowed for generic constant parameter: $1'#000+ - '04129_E_Can'#039't read or write variables of',' this type in iso mode'#000+ + '04128_E_Type not all','owed for generic constant parameter: $1'#000+ + '04129_E_Can'#039't read or write variables of this type in iso mode'#000+ '05000_E_Identifier not found "$1"'#000+ '05001_F_Internal Error in SymTableStack()'#000+ '05002_E_Duplicate identifier "$1"'#000+ - '05003_H_Identifier already defined in $1 at line $2'#000+ + '05003_H_Identifier already ','defined in $1 at line $2'#000+ '05004_E_Unknown identifier "$1"'#000+ - '05005_E_Forward declara','tion not solved "$1"'#000+ + '05005_E_Forward declaration not solved "$1"'#000+ '05007_E_Error in type definition'#000+ '05009_E_Forward type not resolved "$1"'#000+ - '05010_E_Only static variables can be used in static methods or outside'+ - ' methods'#000+ + '05010_E_Only static variables can be used in static methods or outs','i'+ + 'de methods'#000+ '05012_E_Record or object or class type expected'#000+ - '05013_E_Instances of',' classes or objects with an abstract method are '+ - 'not allowed'#000+ + '05013_E_Instances of classes or objects with an abstract method are no'+ + 't allowed'#000+ '05014_W_Label not defined "$1"'#000+ '05015_E_Label used but not defined "$1"'#000+ - '05016_E_Illegal label declaration'#000+ + '05016_E_Illegal label declara','tion'#000+ '05017_E_GOTO and LABEL are not supported (use switch -Sg)'#000+ - '05018_E_Label not',' found'#000+ + '05018_E_Label not found'#000+ '05019_E_Identifier isn'#039't a label'#000+ '05020_E_Label already defined'#000+ '05021_E_Illegal type declaration of set elements'#000+ - '05022_E_Forward class definition not resolved "$1"'#000+ + '05022_E_Forward class definition not reso','lved "$1"'#000+ '05023_H_Unit "$1" not used in $2'#000+ '05024_H_Parameter "$1" not used'#000+ - '05025','_N_Local variable "$1" not used'#000+ + '05025_N_Local variable "$1" not used'#000+ '05026_H_Value parameter "$1" is assigned but never used'#000+ '05027_N_Local variable "$1" is assigned but never used'#000+ - '05028_H_Local $1 "$2" is not used'#000+ + '05028_H_Local $1 ','"$2" is not used'#000+ '05029_N_Private field "$1.$2" is never used'#000+ - '05030_N_Private fie','ld "$1.$2" is assigned but never used'#000+ + '05030_N_Private field "$1.$2" is assigned but never used'#000+ '05031_N_Private method "$1.$2" never used'#000+ '05032_E_Set type expected'#000+ '05033_W_Function result does not seem to be set'#000+ - '05034_W_Type "$1" is not aligned correctly in current record for C'#000+ - '05035_E_Unknown rec','ord field identifier "$1"'#000+ + '05034_','W_Type "$1" is not aligned correctly in current record for C'#000+ + '05035_E_Unknown record field identifier "$1"'#000+ '05036_W_Local variable "$1" does not seem to be initialized'#000+ '05037_W_Variable "$1" does not seem to be initialized'#000+ - '05038_E_Identifier idents no member "$1"'#000+ + '05038_E_Identifier i','dents no member "$1"'#000+ '05039_H_Found declaration: $1'#000+ - '05040_E_Data element too larg','e'#000+ + '05040_E_Data element too large'#000+ '05042_E_No matching implementation for interface method "$1" found'#000+ '05043_W_Symbol "$1" is deprecated'#000+ '05044_W_Symbol "$1" is not portable'#000+ - '05055_W_Symbol "$1" is not implemented'#000+ + '05055_W_Symbol "$1" i','s not implemented'#000+ '05056_E_Can'#039't create unique type from this type'#000+ - '05057_H_Local ','variable "$1" does not seem to be initialized'#000+ + '05057_H_Local variable "$1" does not seem to be initialized'#000+ '05058_H_Variable "$1" does not seem to be initialized'#000+ - '05059_W_Function result variable does not seem to be initialized'#000+ + '05059_W_Function result variable does not seem to be initial','ized'#000+ '05060_H_Function result variable does not seem to be initialized'#000+ - '05061_W_Va','riable "$1" read but nowhere assigned'#000+ + '05061_W_Variable "$1" read but nowhere assigned'#000+ '05062_H_Found abstract method: $1'#000+ '05063_W_Symbol "$1" is experimental'#000+ - '05064_W_Forward declaration "$1" not resolved, assumed external'#000+ + '05064_W_Forward declaration "$1" not resolved, assum','ed external'#000+ '05065_W_Symbol "$1" is belongs to a library'#000+ - '05066_W_Symbol "$1" is d','eprecated: "$2"'#000+ + '05066_W_Symbol "$1" is deprecated: "$2"'#000+ '05067_E_Cannot find an enumerator for the type "$1"'#000+ '05068_E_Cannot find a "MoveNext" method in enumerator "$1"'#000+ - '05069_E_Cannot find a "Current" property in enumerator "$1"'#000+ - '05070_E_Mismatch between number of declared parameter','s and number of'+ - ' colons in message string.'#000+ + '05069_E_Cannot find a "Current" p','roperty in enumerator "$1"'#000+ + '05070_E_Mismatch between number of declared parameters and number of c'+ + 'olons in message string.'#000+ '05071_N_Private type "$1.$2" never used'#000+ '05072_N_Private const "$1.$2" never used'#000+ - '05073_N_Private property "$1.$2" never used'#000+ + '05073_N_Private property "$1.$2" neve','r used'#000+ '05074_W_Unit "$1" is deprecated'#000+ '05075_W_Unit "$1" is deprecated: "$2"'#000+ - '050','76_W_Unit "$1" is not portable'#000+ + '05076_W_Unit "$1" is not portable'#000+ '05077_W_Unit "$1" is belongs to a library'#000+ '05078_W_Unit "$1" is not implemented'#000+ '05079_W_Unit "$1" is experimental'#000+ - '05080_E_No full definition of the formally declared class "$1" is in s'+ - 'cope. Add the unit contain','ing its full definition to the uses clause'+ + '05080_E_No full ','definition of the formally declared class "$1" is in'+ + ' scope. Add the unit containing its full definition to the uses clause'+ '.'#000+ '05081_E_Gotos into initialization or finalization blocks of units are '+ 'not allowed'#000+ - '05082_E_Invalid external name "$1" for formal class "$2"'#000+ - '05083_E_Complete class definition with external name "$1"',' here'#000+ + '05082_E_Invalid external name "$1"',' for formal class "$2"'#000+ + '05083_E_Complete class definition with external name "$1" here'#000+ '05084_W_Possible library conflict: symbol "$1" from library "$2" also '+ 'found in library "$3"'#000+ - '05085_E_Cannot add implicit constructor '#039'Create'#039' because ident'+ + '05085_E_Cannot add implicit constructor '#039'Create'#039' because ident', 'ifier already used by "$1"'#000+ - '05086_E_Cannot generate default constructor for class',', because paren'+ - 't has no parameterless constructor'#000+ + '05086_E_Cannot generate default constructor for class, because parent '+ + 'has no parameterless constructor'#000+ '05087_D_Adding helper for $1'#000+ '05088_E_Found declaration: $1'#000+ - '05089_W_Local variable "$1" of a managed type does not seem to be init'+ - 'ialized'#000+ - '05090_W_Variable "$1" of a managed type does not seem',' to be initiali'+ - 'zed'#000+ + '05089_W_Local variable "$1" of a managed type does ','not seem to be in'+ + 'itialized'#000+ + '05090_W_Variable "$1" of a managed type does not seem to be initialize'+ + 'd'#000+ '05091_H_Local variable "$1" of a managed type does not seem to be init'+ 'ialized'#000+ - '05092_H_Variable "$1" of a managed type does not seem to be initialize'+ - 'd'#000+ + '05092_H_Variable "$1" of a managed type does not seem to be ini','tiali'+ + 'zed'#000+ '05093_W_Function result variable of a managed type does not seem to be'+ - ' ','initialized'#000+ + ' initialized'#000+ '05094_H_Function result variable of a managed type does not seem to be'+ ' initialized'#000+ '05095_W_Duplicate identifier "$1"'#000+ - '05096_E_Generic type parameter "$1" does not match with the one in the'+ - ' declaration'#000+ - '05097_E_Generic type paramet','er declared as "$1"'#000+ + '05096_E_Generic type parameter ','"$1" does not match with the one in t'+ + 'he declaration'#000+ + '05097_E_Generic type parameter declared as "$1"'#000+ '05098_E_Record or object type expected'#000+ '06009_E_Parameter list size exceeds 65535 bytes'#000+ '06012_E_File types must be var parameters'#000+ - '06013_E_The use of a far pointer isn'#039't allowed there'#000+ - '06015_E_EXPORT declared functions cann','ot be called'#000+ + '06013_E_The',' use of a far pointer isn'#039't allowed there'#000+ + '06015_E_EXPORT declared functions cannot be called'#000+ '06016_W_Possible illegal call of constructor or destructor'#000+ '06017_N_Inefficient code'#000+ '06018_W_Unreachable code'#000+ - '06020_E_Abstract methods cannot be called directly'#000+ + '06020_E_Abstract methods cannot be cal','led directly'#000+ '06027_DL_Register $1 weight $2 $3'#000+ '06029_DL_Stack frame is omitted'#000+ - '0','6031_E_Object or class methods cannot be inline.'#000+ + '06031_E_Object or class methods cannot be inline.'#000+ '06032_E_Procvar calls cannot be inline.'#000+ '06033_E_No code for inline procedure stored'#000+ - '06035_E_Element zero of an ansi/wide- or longstring cannot be accessed'+ - ', use (set)length instead'#000+ - '06037_E_Con','structors or destructors cannot be called inside a '#039'w'+ - 'ith'#039' clause'#000+ + '06035_E_Element zero of an ','ansi/wide- or longstring cannot be access'+ + 'ed, use (set)length instead'#000+ + '06037_E_Constructors or destructors cannot be called inside a '#039'wit'+ + 'h'#039' clause'#000+ '06038_E_Cannot call message handler methods directly'#000+ - '06039_E_Jump in or outside of an exception block'#000+ + '06039_E_Jump in or outside of an exception',' block'#000+ '06040_E_Control flow statements are not allowed in a finally block'#000+ - '06041_','W_Parameters size exceeds limit for certain cpu'#039's'#000+ + '06041_W_Parameters size exceeds limit for certain cpu'#039's'#000+ '06042_W_Local variable size exceed limit for certain cpu'#039's'#000+ - '06043_E_Local variables size exceeds supported limit'#000+ + '06043_E_Local variables size exceeds supported limi','t'#000+ '06044_E_BREAK not allowed'#000+ '06045_E_CONTINUE not allowed'#000+ - '06046_F_Unknown compile','rproc "$1". Check if you use the correct run '+ - 'time library.'#000+ + '06046_F_Unknown compilerproc "$1". Check if you use the correct run ti'+ + 'me library.'#000+ '06047_F_Cannot find system type "$1". Check if you use the correct run'+ ' time library.'#000+ - '06048_H_Inherited call to abstract method ignored'#000+ - '06049_E_Goto label "$1" not defined or optimiz','ed away'#000+ + '06048_H_Inherite','d call to abstract method ignored'#000+ + '06049_E_Goto label "$1" not defined or optimized away'#000+ '06050_F_Cannot find type "$1" in unit "$2". Check if you use the corre'+ 'ct run time library.'#000+ - '06051_E_Interprocedural gotos are allowed only to outer subroutines'#000+ + '06051_E_Interprocedural gotos are allowed only to outer subro','utines'#000+ '06052_E_Label must be defined in the same scope as it is declared'#000+ - '06053_E','_Leaving procedures containing explicit or implicit exception'+ - 's frames using goto is not allowed'#000+ - '06054_E_In ISO mode, the mod operator is defined only for positive quo'+ - 'tient'#000+ + '06053_E_Leaving procedures containing explicit or implicit exceptions '+ + 'frames using goto is not allowed'#000+ + '06054_E_In ISO mode, the mod operator is defined only for positi','ve q'+ + 'uotient'#000+ '06055_DL_Auto inlining: $1'#000+ - '06056_E_The function used, is not support','ed by the selected instruct'+ - 'ion set: $1'#000+ + '06056_E_The function used, is not supported by the selected instructio'+ + 'n set: $1'#000+ '06057_F_Maximum number of units ($1) reached for the current target'#000+ - '06058_N_Call to subroutine "$1" marked as inline is not inlined'#000+ - '06059_E_Case statement does not handle ordinal value "$1", and no els', - 'e/otherwise statement is present.'#000+ + '06058_N_Call to subroutine "$1" marked as inline is n','ot inlined'#000+ + '06059_E_Case statement does not handle ordinal value "$1", and no else'+ + '/otherwise statement is present.'#000+ '06060_W_Case statement does not handle all possible cases'#000+ - '06061_W_The current subroutine "$1" cannot be compiled for the target '+ - 'CPU, creating dummy'#000+ - '06062_W_The target CPU does not support preserving the reg','isters in '+ - 'subroutine "$1"'#000+ + '06061_W_The current subroutine "$1" cannot be compiled for the targe','t'+ + ' CPU, creating dummy'#000+ + '06062_W_The target CPU does not support preserving the registers in su'+ + 'broutine "$1"'#000+ '07000_DL_Starting $1 styled assembler parsing'#000+ '07001_DL_Finished $1 styled assembler parsing'#000+ '07002_E_Non-label pattern contains @'#000+ - '07004_E_Error building record offset'#000+ + '07004','_E_Error building record offset'#000+ '07005_E_OFFSET used without identifier'#000+ - '07006_E_T','YPE used without identifier'#000+ + '07006_E_TYPE used without identifier'#000+ '07007_E_Cannot use local variable or parameters here'#000+ '07008_E_Need to use OFFSET here'#000+ '07009_E_Need to use $ here'#000+ - '07010_E_Cannot use multiple relocatable symbols'#000+ + '07010_E_Cannot use m','ultiple relocatable symbols'#000+ '07011_E_Relocatable symbol can only be added'#000+ - '07012_E','_Invalid constant expression'#000+ + '07012_E_Invalid constant expression'#000+ '07013_E_Relocatable symbol is not allowed'#000+ '07014_E_Invalid reference syntax'#000+ '07015_E_You cannot reach $1 from that code'#000+ - '07016_E_Local symbols/labels are not allowed as references'#000+ - '07017_E_Invalid base and index reg','ister usage'#000+ + '07016_E_Local',' symbols/labels are not allowed as references'#000+ + '07017_E_Invalid base and index register usage'#000+ '07018_W_Possible error in object field handling'#000+ '07019_E_Wrong scale factor specified'#000+ '07020_E_Multiple index register usage'#000+ - '07021_E_Invalid operand type'#000+ + '07021_E_Invalid operand t','ype'#000+ '07022_E_Invalid string as opcode operand: $1'#000+ - '07023_W_@CODE and @DATA not sup','ported'#000+ + '07023_W_@CODE and @DATA not supported'#000+ '07024_E_Null label references are not allowed'#000+ '07025_E_Divide by zero in asm evaluator'#000+ '07026_E_Illegal expression'#000+ '07027_E_Escape sequence ignored: $1'#000+ - '07028_E_Invalid symbol reference'#000+ - '07029_W_Fwait can cause emulation problems with emu','387'#000+ + '0702','8_E_Invalid symbol reference'#000+ + '07029_W_Fwait can cause emulation problems with emu387'#000+ '07030_W_$1 without operand translated into $1P'#000+ '07031_W_ENTER instruction is not supported by Linux kernel'#000+ - '07032_W_Calling an overload function in assembler'#000+ + '07032_W_Calling an overload function in assembler'#000, '07033_E_Unsupported symbol type for operand'#000+ - '07034_E_Constant value out of bounds',#000+ + '07034_E_Constant value out of bounds'#000+ '07035_E_Error converting decimal $1'#000+ '07036_E_Error converting octal $1'#000+ '07037_E_Error converting binary $1'#000+ '07038_E_Error converting hexadecimal $1'#000+ - '07039_H_$1 translated to $2'#000+ + '07039_H_$1 tra','nslated to $2'#000+ '07040_W_$1 is associated to an overloaded function'#000+ - '07041_E_Cannot ','use SELF outside a method'#000+ + '07041_E_Cannot use SELF outside a method'#000+ '07042_E_Cannot use OLDEBP outside a nested procedure'#000+ '07043_W_Procedures cannot return any value in asm code'#000+ - '07044_E_SEG not supported'#000+ + '07044_E_SEG not supported'#000, '07045_E_Size suffix and destination or source size do not match'#000+ - '07046_W_Size suf','fix and destination or source size do not match'#000+ + '07046_W_Size suffix and destination or source size do not match'#000+ '07047_E_Assembler syntax error'#000+ '07048_E_Invalid combination of opcode and operands'#000+ - '07049_E_Assembler syntax error in operand'#000+ + '07049_E_Assembler syntax error',' in operand'#000+ '07050_E_Assembler syntax error in constant'#000+ - '07051_E_Invalid String ex','pression'#000+ + '07051_E_Invalid String expression'#000+ '07052_W_Constant with symbol $1 for address which is not on a pointer'#000+ '07053_E_Unrecognized opcode $1'#000+ '07054_E_Invalid or missing opcode'#000+ - '07055_E_Invalid combination of prefix and opcode: $1'#000+ - '07056_E_Invalid combination of override and',' opcode: $1'#000+ + '07055_E_Invalid ','combination of prefix and opcode: $1'#000+ + '07056_E_Invalid combination of override and opcode: $1'#000+ '07057_E_Too many operands on line'#000+ '07058_W_NEAR ignored'#000+ '07059_W_FAR ignored'#000+ '07060_E_Duplicate local symbol $1'#000+ '07061_E_Undefined local symbol $1'#000+ - '07062_E_Unknown label identifier $1'#000+ + '07062','_E_Unknown label identifier $1'#000+ '07063_E_Invalid register name'#000+ - '07064_E_Invalid flo','ating point register name'#000+ + '07064_E_Invalid floating point register name'#000+ '07066_W_Modulo not supported'#000+ '07067_E_Invalid floating point constant $1'#000+ '07068_E_Invalid floating point expression'#000+ - '07069_E_Wrong symbol type'#000+ + '07069_E_Wrong symbol',' type'#000+ '07070_E_Cannot index a local var or parameter with a register'#000+ - '07071_E_Inva','lid segment override expression'#000+ + '07071_E_Invalid segment override expression'#000+ '07072_W_Identifier $1 supposed external'#000+ '07073_E_Strings not allowed as constants'#000+ '07074_E_No type of variable specified'#000+ - '07075_E_Assembler code not returned to text section'#000+ - '07076_E_Not a directive or local symb','ol $1'#000+ + '07075_E_A','ssembler code not returned to text section'#000+ + '07076_E_Not a directive or local symbol $1'#000+ '07077_E_Using a defined name as a local label'#000+ '07078_E_Dollar token is used without an identifier'#000+ '07079_W_32bit constant created for address'#000+ - '07080_N_.align is target specific, use .balign or .p2align'#000+ - '07081_E_Cannot directly access fiel','ds of pointer-based parameters'#000+ + '07080_N_.align',' is target specific, use .balign or .p2align'#000+ + '07081_E_Cannot directly access fields of pointer-based parameters'#000+ '07082_E_Can'#039't access fields of objects/classes directly'#000+ '07083_E_No size specified and unable to determine the size of the oper'+ - 'ands'#000+ + 'and','s'#000+ '07084_E_Cannot use RESULT in this function'#000+ - '07086_W_"$1" without operand transl','ated into "$1 %st,%st(1)"'#000+ + '07086_W_"$1" without operand translated into "$1 %st,%st(1)"'#000+ '07087_W_"$1 %st(n)" translated into "$1 %st,%st(n)"'#000+ '07088_W_"$1 %st(n)" translated into "$1 %st(n),%st"'#000+ - '07089_E_Char < not allowed here'#000+ + '07089_E_Char < not allowed her','e'#000+ '07090_E_Char > not allowed here'#000+ '07093_W_ALIGN not supported'#000+ - '07094_E_Inc and De','c cannot be together'#000+ + '07094_E_Inc and Dec cannot be together'#000+ '07095_E_Invalid register list for MOVEM or FMOVEM'#000+ '07096_E_Reglist invalid for opcode'#000+ '07097_E_Higher cpu mode required ($1)'#000+ - '07098_W_No size specified and unable to determine the size of the oper'+ - 'ands, using DWORD as defau','lt'#000+ + '07098_W_No size ','specified and unable to determine the size of the op'+ + 'erands, using DWORD as default'#000+ '07099_E_Syntax error while trying to parse a shifter operand'#000+ '07100_E_Address of packed component is not at a byte boundary'#000+ - '07101_W_No size specified and unable to determine the size of the oper'+ - 'ands, using BYTE as default'#000+ - '07102_W_Use of $','1 for parameters invalid here'#000+ + '07101_W_No size specified and unab','le to determine the size of the op'+ + 'erands, using BYTE as default'#000+ + '07102_W_Use of $1 for parameters invalid here'#000+ '07103_W_Use of $1 is not compatible with regcall convention'#000+ '07104_W_Use of $1 is not recommended for local variable access'#000+ - '07105_W_Use of $1, access may cause a crash or value may be lost'#000+ - '07106_E_VMTOffset must',' be used in combination with a virtual method,'+ - ' and "$1" is not virtual'#000+ + '07105_W','_Use of $1, access may cause a crash or value may be lost'#000+ + '07106_E_VMTOffset must be used in combination with a virtual method, a'+ + 'nd "$1" is not virtual'#000+ '07107_E_Generating PIC, but reference is not PIC-safe'#000+ - '07108_E_All registers in a register set must be of the same kind and w'+ - 'idth'#000+ + '07108_E_All registers in a register',' set must be of the same kind and'+ + ' width'#000+ '07109_E_A register set cannot be empty'#000+ - '0','7110_W_@GOTPCREL is useless and potentially dangerous for local sym'+ - 'bols'#000+ + '07110_W_@GOTPCREL is useless and potentially dangerous for local symbo'+ + 'ls'#000+ '07111_W_Constant with general purpose segment register'#000+ - '07112_E_Invalid offset value for $1'#000+ + '07112_E_Invalid offset value for ','$1'#000+ '07113_E_Invalid register for $1'#000+ - '07114_E_SEH directives are allowed only in pu','re assembler procedures'+ - #000+ + '07114_E_SEH directives are allowed only in pure assembler procedures'#000+ '07115_E_Directive "$1" is not supported for the current target'#000+ '07116_E_This function'#039's result location cannot be encoded directly'+ - ' in a single operand when "nostackframe" is used'#000+ - '07117_E_GOTPCREL references in Intel a','ssembler syntax cannot contain'+ - ' a base or index register, and their offset must 0.'#000+ + ' in a s','ingle operand when "nostackframe" is used'#000+ + '07117_E_GOTPCREL references in Intel assembler syntax cannot contain a'+ + ' base or index register, and their offset must 0.'#000+ '07118_E_The current target does not support GOTPCREL relocations'#000+ - '07119_W_Exported/global symbols should be accessed via the GOT'#000+ - '07120_W_Check size of memory o','perand "$1"'#000+ + '07119_W_Expor','ted/global symbols should be accessed via the GOT'#000+ + '07120_W_Check size of memory operand "$1"'#000+ '07121_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+ 'ts, but expected [$3 bits]"'#000+ - '07122_W_Check size of memory operand "$1: memory-operand-size is $2 bi'+ - 'ts, but expected [$3 bits + $4 byte offset]"'#000+ - '07123_W_Check "','$1: offset of memory operand is negative "$2 byte"'#000+ + '07122_W_Check size of memory operand "$1: memory-o','perand-size is $2 '+ + 'bits, but expected [$3 bits + $4 byte offset]"'#000+ + '07123_W_Check "$1: offset of memory operand is negative "$2 byte"'#000+ '07124_W_Check "$1: size of memory operand is empty, but es exists diff'+ - 'erent definitions of the memory size =>> map to $2 (smallest option)"'#000+ - '07125_E_Invalid register used in memory reference',' expression: "$1"'#000+ + 'erent definitions of the memory size =>','> map to $2 (smallest option)'+ + '"'#000+ + '07125_E_Invalid register used in memory reference expression: "$1"'#000+ '07126_E_SEG used without identifier'#000+ '07127_E_@CODE and @DATA can only be used with the SEG operator'#000+ - '07128_E_Not enough space (16 bits required) for the segment constant o'+ - 'f symbol $1'#000+ - '07129_E_Invalid value of .code directive ','constant'#000+ + '07128_E_Not enough space (16 bits required)',' for the segment constant'+ + ' of symbol $1'#000+ + '07129_E_Invalid value of .code directive constant'#000+ '07130_W_No size specified and unable to determine the size of the cons'+ 'tant, using BYTE as default'#000+ - '07131_W_No size specified and unable to determine the size of the cons'+ - 'tant, using WORD as default'#000+ - '07132_E_Cannot override ES segment'#000, + '07131_W_No size specified and unable to determine the',' size of the co'+ + 'nstant, using WORD as default'#000+ + '07132_E_Cannot override ES segment'#000+ '07133_W_Reference is not valid here (expected "$1")'#000+ '07134_E_Address sizes do not match'#000+ '07135_E_Instruction "POP CS" is not valid for the current target'#000+ - '07136_W_Instruction "POP CS" is not portable (it only works on 8086 an'+ - 'd 8088 CPUs)'#000+ - '07137','_E_Label $1 can only be declared public before it'#039's defined'+ - #000+ + '07136_W_','Instruction "POP CS" is not portable (it only works on 8086 '+ + 'and 8088 CPUs)'#000+ + '07137_E_Label $1 can only be declared public before it'#039's defined'#000+ '07138_E_Local label $1 cannot be declared public'#000+ '07139_E_Cannot use multiple segment overrides'#000+ - '07140_W_Multiple segment overrides (only the last one will take effect'+ - ')'#000+ - '07141_W_Segme','nt base $1 will be generated, but is ignored by the CPU'+ - ' in 64-bit mode'#000+ + '07140','_W_Multiple segment overrides (only the last one will take effe'+ + 'ct)'#000+ + '07141_W_Segment base $1 will be generated, but is ignored by the CPU i'+ + 'n 64-bit mode'#000+ '07142_E_Mismatch broadcasting elements (expected: {$1} found: {$2})'#000+ - '07143_E_Invalid arrangement specifier "$1"'#000+ + '07143_E_Invalid arran','gement specifier "$1"'#000+ '07144_E_Registers in a register set must be consecutive.'#000+ - '0','7145_E_Not supported combination opcode: $1 - att-suffix-type {$2} '+ - 'and memrefsize-type {$3}'#000+ + '07145_E_Not supported combination opcode: $1 - att-suffix-type {$2} an'+ + 'd memrefsize-type {$3}'#000+ '08000_F_Too many assembler files'#000+ - '08001_F_Selected assembler output not supported'#000+ + '08001_F_Selected assembler output n','ot supported'#000+ '08002_F_Comp not supported'#000+ - '08003_F_Direct not support for binary wr','iters'#000+ + '08003_F_Direct not support for binary writers'#000+ '08004_E_Allocating of data is only allowed in bss section'#000+ '08005_F_No binary writer selected'#000+ '08006_E_Asm: Opcode $1 not in table'#000+ - '08007_E_Asm: $1 invalid combination of opcode and operands'#000+ + '08007_E_Asm: $1 invalid co','mbination of opcode and operands'#000+ '08008_E_Asm: 16 Bit references not supported'#000+ - '08','009_E_Asm: Invalid effective address'#000+ + '08009_E_Asm: Invalid effective address'#000+ '08010_E_Asm: Immediate or reference expected'#000+ '08011_E_Asm: $1 value exceeds bounds $2'#000+ - '08012_E_Asm: Short jump is out of range $1'#000+ + '08012_E_Asm: Short jump is out of rang','e $1'#000+ '08013_E_Asm: Undefined label $1'#000+ - '08014_E_Asm: Comp type not supported for th','is target'#000+ + '08014_E_Asm: Comp type not supported for this target'#000+ '08015_E_Asm: Extended type not supported for this target'#000+ '08016_E_Asm: Duplicate label $1'#000+ '08017_E_Asm: Redefined label $1'#000+ - '08018_E_Asm: First defined here'#000+ + '08018_E_Asm: First defined he','re'#000+ '08019_E_Asm: Invalid register $1'#000+ - '08020_E_Asm: 16 or 32 Bit references not sup','ported'#000+ + '08020_E_Asm: 16 or 32 Bit references not supported'#000+ '08021_E_Asm: 64 Bit operands not supported'#000+ '08022_E_Asm: AH,BH,CH or DH cannot be used in an instruction requiring'+ ' REX prefix'#000+ - '08023_E_Missing .seh_endprologue directive'#000+ + '08023_E_Missing .seh_endprol','ogue directive'#000+ '08024_E_Function prologue exceeds 255 bytes'#000+ - '08025_E_.seh_handlerd','ata directive without preceding .seh_handler'#000+ + '08025_E_.seh_handlerdata directive without preceding .seh_handler'#000+ '08026_F_Relocation count for section $1 exceeds 65535'#000+ - '08027_N_Change of bind type of symbol $1 from $2 to $3 after use'#000+ + '08027_N_Change of bind type of symbol $1 from $2 to $3 after ','use'#000+ '08028_H_Change of bind type of symbol $1 from $2 to $3 after use'#000+ - '08029_E_Asm',': 32 Bit references not supported'#000+ + '08029_E_Asm: 32 Bit references not supported'#000+ '08030_F_Code segment too large'#000+ '08031_F_Data segment too large'#000+ - '08032_E_Instruction not supported by the selected instruction set'#000+ + '08032_E_Instruction not supported by the selected instruction se','t'#000+ '08033_E_Asm: conditional branch destination is out of range'#000+ - '08034_E_Asm: RIP c','annot be used as index register or with another re'+ - 'gister in a reference'#000+ + '08034_E_Asm: RIP cannot be used as index register or with another regi'+ + 'ster in a reference'#000+ '08035_F_Illegal function size for SEH function'#000+ - '09000_W_Source operating system redefined'#000+ + '09000_W_Source operating system redefined',#000+ '09001_I_Assembling (pipe) $1'#000+ '09002_E_Can'#039't create assembler file: $1'#000+ - '09003_E_Ca','n'#039't create object file: $1 (error code: $2)'#000+ + '09003_E_Can'#039't create object file: $1 (error code: $2)'#000+ '09004_E_Can'#039't create archive file: $1'#000+ '09005_E_Assembler $1 not found, switching to external assembling'#000+ - '09006_T_Using assembler: $1'#000+ + '09006_T_Using',' assembler: $1'#000+ '09007_E_Error while assembling exitcode $1'#000+ - '09008_E_Can'#039't call the',' assembler, error $1 switching to external'+ - ' assembling'#000+ + '09008_E_Can'#039't call the assembler, error $1 switching to external a'+ + 'ssembling'#000+ '09009_I_Assembling $1'#000+ '09010_I_Assembling with smartlinking $1'#000+ - '09011_W_Object $1 not found, Linking may fail !'#000+ + '09011_W_Object $1 not found, Linking may fai','l !'#000+ '09012_W_Library $1 not found, Linking may fail !'#000+ - '09013_E_Error while linking',#000+ + '09013_E_Error while linking'#000+ '09014_E_Can'#039't call the linker, switching to external linking'#000+ '09015_I_Linking $1'#000+ '09016_E_Util $1 not found, switching to external linking'#000+ - '09017_T_Using util $1'#000+ + '09017_T_Using util $1'#000, '09018_E_Creation of Executables not supported'#000+ - '09019_E_Creation of Dynamic/Shared',' Libraries not supported'#000+ + '09019_E_Creation of Dynamic/Shared Libraries not supported'#000+ '09035_E_Creation of Static Libraries not supported'#000+ '09020_I_Closing script $1'#000+ - '09021_E_Resource compiler "$1" not found, switching to external mode'#000+ + '09021_E_Resource compiler "$1" not found, switching to ext','ernal mode'+ + #000+ '09022_I_Compiling resource $1'#000+ - '09023_T_Unit $1 cannot be statically li','nked, switching to smart link'+ - 'ing'#000+ + '09023_T_Unit $1 cannot be statically linked, switching to smart linkin'+ + 'g'#000+ '09024_T_Unit $1 cannot be smart linked, switching to static linking'#000+ - '09025_T_Unit $1 cannot be shared linked, switching to static linking'#000+ + '09025_T_Unit $1 cannot be shared linked, switching to stati','c linking'+ + #000+ '09026_E_Unit $1 cannot be smart or static linked'#000+ - '09027_E_Unit $1 canno','t be shared or static linked'#000+ + '09027_E_Unit $1 cannot be shared or static linked'#000+ '09028_D_Calling resource compiler "$1" with "$2" as command line'#000+ '09029_E_Error while compiling resources'#000+ - '09030_E_Can'#039't call the resource compiler "$1", switching to extern'+ - 'al mode'#000+ - '09031_E_Can'#039't open resource file',' "$1"'#000+ + '09030_E_Can'#039't call the res','ource compiler "$1", switching to exte'+ + 'rnal mode'#000+ + '09031_E_Can'#039't open resource file "$1"'#000+ '09032_E_Can'#039't write resource file "$1"'#000+ '09033_N_File "$1" not found for backquoted cat command'#000+ - '09034_W_"$1" not found, this will probably cause a linking failure'#000+ + '09034_W_"$1" not found, this will probably cause a linking f','ailure'#000+ '09128_F_Can'#039't post process executable $1'#000+ - '09129_F_Can'#039't open executable $1',#000+ + '09129_F_Can'#039't open executable $1'#000+ '09130_X_Size of Code: $1 bytes'#000+ '09131_X_Size of initialized data: $1 bytes'#000+ '09132_X_Size of uninitialized data: $1 bytes'#000+ '09133_X_Stack space reserved: $1 bytes'#000+ - '09134_X_Stack space committed: $1 bytes'#000+ - '09200_F_Executable image size is too big ','for $1 target.'#000+ + '0','9134_X_Stack space committed: $1 bytes'#000+ + '09200_F_Executable image size is too big for $1 target.'#000+ '09201_W_Object file "$1" contains 32-bit absolute relocation to symbol'+ ' "$2".'#000+ '09202_E_Program segment too large (exceeds 64k by $1 bytes)'#000+ - '09203_E_Code segment "$1" too large (exceeds 64k by $2 bytes)'#000+ - '09204_E_Data segment "$1" ','too large (exceeds 64k by $2 bytes)'#000+ + '09203_E_','Code segment "$1" too large (exceeds 64k by $2 bytes)'#000+ + '09204_E_Data segment "$1" too large (exceeds 64k by $2 bytes)'#000+ '09205_E_Segment "$1" too large (exceeds 64k by $2 bytes)'#000+ '09206_E_Group "$1" too large (exceeds 64k by $2 bytes)'#000+ - '09207_E_Cannot create a .COM file, because the program contains segmen'+ - 't relocations'#000+ - '09208_W_','Program "$1" uses experimental CheckPointer option'#000+ + '09207_E_Cann','ot create a .COM file, because the program contains segm'+ + 'ent relocations'#000+ + '09208_W_Program "$1" uses experimental CheckPointer option'#000+ '09209_E_Multiple defined symbol "$1"'#000+ '09210_E_COMDAT selection mode $1 not supported (section: "$1")'#000+ - '09211_E_Associative section expected for COMDAT section "$1"'#000+ - '09212_E_COMDAT section selec','tion mode doesn'#039't match for section '+ - '"$1" and symbol "$2"'#000+ + '09211_E_A','ssociative section expected for COMDAT section "$1"'#000+ + '09212_E_COMDAT section selection mode doesn'#039't match for section "$'+ + '1" and symbol "$2"'#000+ '09213_E_Associative COMDAT section for section "$1" not found'#000+ - '09214_D_Discarding duplicate symbol "$1" due to COMDAT selection mode'#000+ - '09215_D_Discarding duplicate symbol "$1" with same ','size due to COMDA'+ - 'T selection mode'#000+ + '09214_D_Discarding duplicate symbol "$1" ','due to COMDAT selection mod'+ + 'e'#000+ + '09215_D_Discarding duplicate symbol "$1" with same size due to COMDAT '+ + 'selection mode'#000+ '09216_D_Discarding duplicate symbol "$1" with same content due to COMD'+ 'AT selection mode'#000+ - '09217_D_Replacing duplicate symbol "$1" with smaller size due to COMDA'+ - 'T selection mode'#000+ - '09218_E_Size of duplicate COMDA','T symbol "$1" differs'#000+ + '09217_D_Replacing duplicate symbol "$1','" with smaller size due to COM'+ + 'DAT selection mode'#000+ + '09218_E_Size of duplicate COMDAT symbol "$1" differs'#000+ '09219_E_Content of duplicate COMDAT symbol "$1" differs'#000+ '09220_E_COMDAT selection mode for symbol "$1" differs'#000+ - '09221_E_Undefined symbol: $1 (first seen in $2)'#000+ + '09221_E_Undefined symbol: $1',' (first seen in $2)'#000+ '09222_E_Undefined symbol: $1'#000+ '10000_T_Unitsearch: $1'#000+ - '10001_T_','PPU Loading $1'#000+ + '10001_T_PPU Loading $1'#000+ '10002_U_PPU Name: $1'#000+ '10003_U_PPU Flags: $1'#000+ '10004_U_PPU Crc: $1'#000+ '10005_U_PPU Time: $1'#000+ '10006_U_PPU File too short'#000+ - '10007_U_PPU Invalid Header (no PPU at the begin)'#000+ + '10007_U_PPU Invalid Header (no PPU',' at the begin)'#000+ '10008_U_PPU Invalid Version $1'#000+ - '10009_U_PPU is compiled for anothe','r processor'#000+ + '10009_U_PPU is compiled for another processor'#000+ '10010_U_PPU is compiled for another target'#000+ '10011_U_PPU Source: $1'#000+ '10012_U_Writing $1'#000+ '10013_F_Can'#039't Write PPU-File'#000+ '10014_F_Error reading PPU-File'#000+ - '10015_F_Unexpected end of PPU-File'#000+ + '100','15_F_Unexpected end of PPU-File'#000+ '10016_F_Invalid PPU-File entry: $1'#000+ - '10017_F_PPU D','bx count problem'#000+ + '10017_F_PPU Dbx count problem'#000+ '10018_E_Illegal unit name: $1 (expecting $2)'#000+ '10019_F_Too much units'#000+ '10020_F_Circular unit reference between $1 and $2'#000+ - '10021_F_Can'#039't compile unit $1, no sources available'#000+ + '10021_F_Can'#039't compile uni','t $1, no sources available'#000+ '10022_F_Can'#039't find unit $1 used by $2'#000+ - '10023_W_Unit $1',' was not found but $2 exists'#000+ + '10023_W_Unit $1 was not found but $2 exists'#000+ '10024_F_Unit $1 searched but $2 found'#000+ '10025_W_Compiling the system unit requires the -Us switch'#000+ - '10026_F_There were $1 errors compiling module, stopping'#000+ + '10026_F_There were $1 errors compil','ing module, stopping'#000+ '10027_U_Load from $1 ($2) unit $3'#000+ - '10028_U_Recompiling $1, c','hecksum changed for $2'#000+ + '10028_U_Recompiling $1, checksum changed for $2'#000+ '10029_U_Recompiling $1, source found only'#000+ '10030_U_Recompiling unit, static lib is older than ppufile'#000+ - '10031_U_Recompiling unit, shared lib is older than ppufile'#000+ - '10032_U_Recompiling unit, obj and asm are older than ppuf','ile'#000+ + '10031_U_Recompiling unit, shared lib',' is older than ppufile'#000+ + '10032_U_Recompiling unit, obj and asm are older than ppufile'#000+ '10033_U_Recompiling unit, obj is older than asm'#000+ '10034_U_Parsing interface of $1'#000+ '10035_U_Parsing implementation of $1'#000+ '10036_U_Second load for unit $1'#000+ - '10037_U_PPU Check file $1 time $2'#000+ - '10040_W_Can'#039't recompile unit $1, but found modified i','nclude file'+ - 's'#000+ + '10037_U','_PPU Check file $1 time $2'#000+ + '10040_W_Can'#039't recompile unit $1, but found modified include files'#000+ '10041_U_File $1 is newer than the one used for creating PPU file $2'#000+ '10042_U_Trying to use a unit which was compiled with a different FPU m'+ 'ode'#000+ - '10043_U_Loading interface units from $1'#000+ - '10044_U_Loading implementation units from $1'#000, + '10043','_U_Loading interface units from $1'#000+ + '10044_U_Loading implementation units from $1'#000+ '10045_U_Interface CRC changed for unit $1'#000+ '10046_U_Implementation CRC changed for unit $1'#000+ '10047_U_Finished compiling unit $1'#000+ - '10048_U_Adding dependency: $1 depends on $2'#000+ + '10048_U_Adding dependency: $1 depend','s on $2'#000+ '10049_U_No reload, is caller: $1'#000+ - '10050_U_No reload, already in second co','mpile: $1'#000+ + '10050_U_No reload, already in second compile: $1'#000+ '10051_U_Flag for reload: $1'#000+ '10052_U_Forced reloading'#000+ '10053_U_Previous state of $1: $2'#000+ '10054_U_Already compiling $1, setting second compile'#000+ - '10055_U_Loading unit $1'#000+ + '10055_U_Loa','ding unit $1'#000+ '10056_U_Finished loading unit $1'#000+ '10057_U_Registering new unit $1'#000+ - '10','058_U_Re-resolving unit $1'#000+ + '10058_U_Re-resolving unit $1'#000+ '10059_U_Skipping re-resolving unit $1, still loading used units'#000+ '10060_U_Unloading resource unit $1 (not needed)'#000+ - '10061_E_Unit $1 was compiled using a different whole program optimizat'+ - 'ion feedback input ($2, $3); re','compile it without wpo or use the sam'+ + '10061_E_Unit $1 was c','ompiled using a different whole program optimiz'+ + 'ation feedback input ($2, $3); recompile it without wpo or use the sam'+ 'e wpo feedback input file for this compilation invocation'#000+ - '10062_U_Indirect interface (objects/classes) CRC changed for unit $1'#000+ + '10062_U_Indirect interface (objects/classes) CRC changed for unit',' $1'+ + #000+ '10063_U_PPU is compiled for another i8086 memory model'#000+ - '10064_U_Loading unit ','$1 from package $2'#000+ + '10064_U_Loading unit $1 from package $2'#000+ '10065_F_Internal type "$1" was not found. Check if you use the correct'+ ' run time library.'#000+ - '10066_F_Internal type "$1" does not look as expected. Check if you use'+ - ' the correct run time library.'#000+ - '10067_U_Skipping unit, PPU and ','compiler have to be both compiled wit'+ - 'h or without LLVM support'#000+ + '10066_F_Internal type "$1" does not look as expected','. Check if you u'+ + 'se the correct run time library.'#000+ + '10067_U_Skipping unit, PPU and compiler have to be both compiled with '+ + 'or without LLVM support'#000+ '11000_O_$1 [options] <inputfile> [options]'#000+ - '11001_W_Only one source file supported, changing source file to compil'+ - 'e from "$1" into "$2"'#000+ - '11002_W_DEF file can be created only for O','S/2'#000+ + '11001_W_Only one source file supported, changing sourc','e file to comp'+ + 'ile from "$1" into "$2"'#000+ + '11002_W_DEF file can be created only for OS/2'#000+ '11003_E_Nested response files are not supported'#000+ '11004_F_No source file name in command line'#000+ '11005_N_No option inside $1 config file'#000+ - '11006_E_Illegal parameter: $1'#000+ + '11006_E_Illegal paramete','r: $1'#000+ '11007_H_-? writes help pages'#000+ '11008_F_Too many config files nested'#000+ - '11009_F_','Unable to open file $1'#000+ + '11009_F_Unable to open file $1'#000+ '11010_D_Reading further options from $1'#000+ '11011_W_Target is already set to: $1'#000+ - '11012_W_Shared libs not supported on DOS platform, reverting to static'+ - #000+ - '11013_F_In options file $1 at line $2 too many #IF(N)DEFs encountered', - #000+ + '11012_W_Shared libs not supported on DOS platform, reverting',' to stat'+ + 'ic'#000+ + '11013_F_In options file $1 at line $2 too many #IF(N)DEFs encountered'#000+ '11014_F_In options file $1 at line $2 unexpected #ENDIFs encountered'#000+ '11015_F_Open conditional at the end of the options file'#000+ - '11016_W_Debug information generation is not supported by this executab'+ - 'le'#000+ + '11016_W_Debug information generati','on is not supported by this execut'+ + 'able'#000+ '11017_H_Try recompiling with -dGDB'#000+ - '11018_','W_You are using the obsolete switch $1'#000+ + '11018_W_You are using the obsolete switch $1'#000+ '11019_W_You are using the obsolete switch $1, please use $2'#000+ - '11020_N_Switching assembler to default source writing assembler'#000+ + '11020_N_Switching assembler to default source writing assembl','er'#000+ '11021_W_Assembler output selected "$1" is not compatible with "$2"'#000+ - '11022_W_"$','1" assembler use forced'#000+ + '11022_W_"$1" assembler use forced'#000+ '11026_T_Reading options from file $1'#000+ '11027_T_Reading options from environment $1'#000+ '11028_D_Handling option "$1"'#000+ - '11029_O_*** press enter ***'#000+ + '11029_O_*** press enter **','*'#000+ '11030_H_Start of reading config file $1'#000+ - '11031_H_End of reading config file $1'#000, + '11031_H_End of reading config file $1'#000+ '11032_D_Interpreting option "$1"'#000+ '11036_D_Interpreting firstpass option "$1"'#000+ '11033_D_Interpreting file option "$1"'#000+ '11034_D_Reading config file "$1"'#000+ - '11035_D_Found source file name "$1"'#000+ + '11035_D_Found',' source file name "$1"'#000+ '11039_E_Unknown codepage "$1"'#000+ - '11040_F_Config file $1 is a',' directory'#000+ + '11040_F_Config file $1 is a directory'#000+ '11041_W_Assembler output selected "$1" cannot generate debug info, deb'+ 'ugging disabled'#000+ - '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg instead'#000+ + '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg ins','tead'#000+ '11043_F_In options file $1 at line $2 #ELSE directive without #IF(N)DE'+ - 'F fou','nd'#000+ + 'F found'#000+ '11044_F_Option "$1" is not, or not yet, supported on the current targe'+ 't platform'#000+ '11045_F_The feature "$1" is not, or not yet, supported on the selected'+ - ' target platform'#000+ - '11046_N_DWARF debug information cannot be used with smart linking on ', - 'this target, switching to static linking'#000+ + ' targe','t platform'#000+ + '11046_N_DWARF debug information cannot be used with smart linking on t'+ + 'his target, switching to static linking'#000+ '11047_W_Option "$1" is ignored for the current target platform.'#000+ - '11048_W_Disabling external debug information because it is unsupported'+ - ' for the selected target/debug format combination.'#000+ - '11049_N_DWARF ','debug information cannot be used with smart linking wi'+ - 'th external assembler, disabling static library creation.'#000+ - '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARGET environment variabl'+ - 'e: $1'#000+ - '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TARGET',' environment var'+ - 'iable: $1'#000+ - '11052_E_You must use a FPU type of VFPV2, VFPV3 or VFPV3_D16 when usin'+ - 'g the EABIHF ABI target'#000+ - '11053_W_The selected debug format is not supported on the current targ'+ - 'et, not changing the current setting'#000+ - '11054_E_Argum','ent to "$1" is missing'#000+ + '11048_W_Disabling external debug information because it',' is unsupport'+ + 'ed for the selected target/debug format combination.'#000+ + '11049_N_DWARF debug information cannot be used with smart linking with'+ + ' external assembler, disabling static library creation.'#000+ + '11050_E_Invalid value for MACOSX_DEPLOYMENT_TARG','ET environment varia'+ + 'ble: $1'#000+ + '11051_E_Invalid value for IPHONEOS_DEPLOYMENT_TARGET environment varia'+ + 'ble: $1'#000+ + '11052_E_You must use one of the VFP FPU types when using the EABIHF AB'+ + 'I target'#000+ + '11053_W_The selected debug format is not supported on t','he current ta'+ + 'rget, not changing the current setting'#000+ + '11054_E_Argument to "$1" is missing'#000+ '11055_E_Malformed parameter: $1'#000+ '11056_W_Smart linking requires external linker'#000+ '11057_E_Creating .COM files is not supported in the current memory mod'+ - 'el. Only the tiny memory model supports making .COM files.'#000+ - '11058_W_E','xperimental CheckPointer option not enabled because it is i'+ - 'ncomptatible with -Ur option.'#000+ + 'el.',' Only the tiny memory model supports making .COM files.'#000+ + '11058_W_Experimental CheckPointer option not enabled because it is inc'+ + 'omptatible with -Ur option.'#000+ '11059_E_Unsupported target architecture -P$1, invoke the "fpc" compile'+ - 'r driver instead.'#000+ - '11060_E_Feature switches are only supported while compiling the',' syst'+ - 'em unit.'#000+ + 'r driver instead','.'#000+ + '11060_E_Feature switches are only supported while compiling the system'+ + ' unit.'#000+ '11061_N_The selected debug format is not supported by the internal lin'+ 'ker, switching to external linking'#000+ - '11062_E_You can not use both options ($1) ($2) at same time.'#000+ - '12000_F_Cannot open whole program optimization feedback file',' "$1"'#000+ + '11062_E_You can not use both options ($1) ($2) at same t','ime.'#000+ + '12000_F_Cannot open whole program optimization feedback file "$1"'#000+ '12001_D_Processing whole program optimization information in wpo feedb'+ 'ack file "$1"'#000+ '12002_D_Finished processing the whole program optimization information'+ - ' in wpo feedback file "$1"'#000+ - '12003_E_Expected section header, but got "$2" at line',' $1 of wpo feed'+ - 'back file'#000+ + ' in wpo feedbac','k file "$1"'#000+ + '12003_E_Expected section header, but got "$2" at line $1 of wpo feedba'+ + 'ck file'#000+ '12004_W_No handler registered for whole program optimization section "'+ '$2" at line $1 of wpo feedback file, ignoring'#000+ - '12005_D_Found whole program optimization section "$1" with information'+ - ' about "$2"'#000+ - '12006_F_The selec','ted whole program optimizations require a previousl'+ - 'y generated feedback file (use -Fw to specify)'#000+ + '12005_D_Found whole program optimi','zation section "$1" with informati'+ + 'on about "$2"'#000+ + '12006_F_The selected whole program optimizations require a previously '+ + 'generated feedback file (use -Fw to specify)'#000+ '12007_E_No collected information necessary to perform "$1" whole progr'+ - 'am optimization found'#000+ - '12008_F_Specify a whole program optimization feedb','ack file to store '+ - 'the generated info in (using -FW)'#000+ + 'am opti','mization found'#000+ + '12008_F_Specify a whole program optimization feedback file to store th'+ + 'e generated info in (using -FW)'#000+ '12009_E_Not generating any whole program optimization information, yet'+ ' a feedback file was specified (using -FW)'#000+ - '12010_E_Not performing any whole program optimizations, yet an input f'+ - 'eedba','ck file was specified (using -Fw)'#000+ + '12010_E_No','t performing any whole program optimizations, yet an input'+ + ' feedback file was specified (using -Fw)'#000+ '12011_D_Skipping whole program optimization section "$1", because not '+ 'needed by the requested optimizations'#000+ - '12012_W_Overriding previously read information for "$1" from feedback '+ - 'input file using information',' in section "$2"'#000+ + '12012_W_Overriding previously rea','d information for "$1" from feedbac'+ + 'k input file using information in section "$2"'#000+ '12013_E_Cannot extract symbol liveness information from program when s'+ 'tripping symbols, use -Xs-'#000+ - '12014_E_Cannot extract symbol liveness information from program when w'+ - 'hen not linking'#000+ - '12015_F_Cannot find "$1" or "$2" to extr','act symbol liveness informat'+ - 'ion from linked program'#000+ + '12014_E_Cannot extract symbol liveness information from progr','am when'+ + ' when not linking'#000+ + '12015_F_Cannot find "$1" or "$2" to extract symbol liveness informatio'+ + 'n from linked program'#000+ '12016_E_Error during reading symbol liveness information produced by "'+ '$1"'#000+ - '12017_F_Error executing "$1" (exitcode: $2) to extract symbol informat'+ - 'ion from linked program'#000+ - '12018_E_Collection o','f symbol liveness information can only help when'+ - ' using smart linking, use -CX -XX'#000+ + '12017_F_Error executing "$1" (exitcode: $2) to ex','tract symbol inform'+ + 'ation from linked program'#000+ + '12018_E_Collection of symbol liveness information can only help when u'+ + 'sing smart linking, use -CX -XX'#000+ '12019_E_Cannot create specified whole program optimisation feedback fi'+ 'le "$1"'#000+ - '13001_F_Can'#039't find package $1'#000+ + '13001_F_Can'#039't f','ind package $1'#000+ '13002_U_PCP file for package $1 found'#000+ - '13003_E_Dupl','icate package $1'#000+ + '13003_E_Duplicate package $1'#000+ '13004_E_Unit $1 can not be part of a package'#000+ '13005_N_Unit $1 is implicitely imported into package $2'#000+ '13006_F_Failed to create PCP file $2 for package $1'#000+ - '13007_F_Failed to read PCP file for package $1'#000+ - '13008_T_PCP loading $1'#000, + '13007','_F_Failed to read PCP file for package $1'#000+ + '13008_T_PCP loading $1'#000+ '13009_U_PCP Name: $1'#000+ '13010_U_PCP Flags: $1'#000+ '13011_U_PCP Crc: $1'#000+ '13012_U_PCP Time: $1'#000+ '13013_U_PCP File too short'#000+ '13014_U_PCP Invalid Header (no PCP at the begin)'#000+ - '13015_U_PCP Invalid Version $1'#000+ + '13015_U_PCP Inv','alid Version $1'#000+ '13016_U_PCP is compiled for another processor'#000+ - '130','17_U_PCP is compiled for another target'#000+ + '13017_U_PCP is compiled for another target'#000+ '13018_U_Writing $1'#000+ '13019_F_Can'#039't Write PCP-File'#000+ '13020_F_Error reading PCP-File'#000+ '13021_F_Unexpected end of PCP-File'#000+ - '13022_F_Invalid PCP-File entry: $1'#000+ - '13023_U_Trying to use a unit which was compiled wit','h a different FPU'+ - ' mode'#000+ + '13022_F_Invalid PCP-F','ile entry: $1'#000+ + '13023_U_Trying to use a unit which was compiled with a different FPU m'+ + 'ode'#000+ '13024_T_Packagesearch: $1'#000+ '13025_U_Required package $1'#000+ '13026_U_Contained unit $1'#000+ '13027_E_Unit $1 is already contained in package $2'#000+ - '13028_W_Unit $1 is imported from indirectly required package $2'#000+ - '13029_U_PPL filename $','1'#000+ + '13028_W_Unit $1 is im','ported from indirectly required package $2'#000+ + '13029_U_PPL filename $1'#000+ '11023_Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPC'+ 'CPU'#010+ - 'Copyright (c) 1993-2020 by Florian Klaempfl and others'#000+ - '11024_Free Pascal Compiler version $FPCVERSION'#010+ + 'Copyright (c) 1993-2021 by Florian Klaempfl and others'#000+ + '11024_Free Pascal Compiler version $FPCVERSI','ON'#010+ #010+ 'Compiler date : $FPCDATE'#010+ 'Compiler CPU target: $FPCCPU'#010+ #010+ - 'S','upported targets (targets marked with '#039'{*}'#039' are under devel'+ - 'opment):'#010+ + 'Supported targets (targets marked with '#039'{*}'#039' are under develop'+ + 'ment):'#010+ ' $OSTARGETS'#010+ #010+ 'Supported CPU instruction sets:'#010+ ' $INSTRUCTIONSETS'#010+ #010+ 'Supported FPU instruction sets:'#010+ - ' $FPUINSTRUCTIONSETS'#010+ + ' $FPUINS','TRUCTIONSETS'#010+ #010+ 'Supported inline assembler modes:'#010+ ' $ASMMODES'#010+ #010+ - 'Reco','gnized compiler and RTL features:'#010+ + 'Recognized compiler and RTL features:'#010+ ' $FEATURELIST'#010+ #010+ 'Recognized modeswitches:'#010+ @@ -1427,364 +1430,364 @@ const msgtxt : array[0..000362,1..240] of char=( 'Supported Optimizations:'#010+ ' $OPTIMIZATIONS'#010+ #010+ - 'Supported Whole Program Optimizations:'#010+ + 'Su','pported Whole Program Optimizations:'#010+ ' All'#010+ ' $WPOPTIMIZATIONS'#010+ #010+ - 'Co','de Generation Backend'#010+ + 'Code Generation Backend'#010+ ' $CODEGENERATIONBACKEND'#010+ #010+ 'Supported Microcontroller types:$\n $CONTROLLERTYPES$\n'#010+ 'This program comes under the GNU General Public Licence'#010+ - 'For more information read COPYING.v2'#010+ + 'For more infor','mation read COPYING.v2'#010+ #010+ - 'Please report bugs in our bug tracker on:',#010+ + 'Please report bugs in our bug tracker on:'#010+ ' https://bugs.freepascal.org'#010+ #010+ 'More information may be found on our WWW pages (including directions'#010+ - 'for mailing lists useful for asking questions or discussing potential'#010+ + 'for mailing lists useful for asking questions or discussing',' potentia'+ + 'l'#010+ 'new features, etc.):'#010+ - ' https://www.free','pascal.org'#000+ + ' https://www.freepascal.org'#000+ '11025_F*0*_Only options valid for the default or selected platform are'+ ' listed.'#010+ '**0*_Put + after a boolean switch option to enable it, - to disable it'+ '.'#010+ - '**1@<x>_Read compiler options from <x> in addition to the default fpc.'+ - 'cfg'#010+ - '**1a','_The compiler does not delete the generated assembler file'#010+ + '**1@<x>_Read ','compiler options from <x> in addition to the default fp'+ + 'c.cfg'#010+ + '**1a_The compiler does not delete the generated assembler file'#010+ '**2a5_Don'#039't generate Big Obj COFF files for GNU Binutils older tha'+ 'n 2.25 (Windows, NativeNT)'#010+ - '**2al_List sourcecode lines in assembler file'#010+ - '**2an_List node info in assembler file (-d','EXTDEBUG compiler)'#010+ + '**2al_List sourcecode l','ines in assembler file'#010+ + '**2an_List node info in assembler file (-dEXTDEBUG compiler)'#010+ '**2ao_Add an extra option to external assembler call (ignored for inte'+ 'rnal)'#010+ '*L2ap_Use pipes instead of creating temporary assembler files'#010+ - '**2ar_List register allocation/release info in assembler file'#010+ - '**2at_List temp alloc','ation/release info in assembler file'#010+ + '**2ar_List registe','r allocation/release info in assembler file'#010+ + '**2at_List temp allocation/release info in assembler file'#010+ '**1A<x>_Output format:'#010+ '**2Adefault_Use default assembler'#010+ '3*2Aas_Assemble using GNU AS'#010+ '3*2Aas-darwin_Assemble Darwin Mach-O using GNU GAS'#010+ - '3*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer'#010+ - '8*2A','nasm_Assemble using Nasm'#010+ + '3','*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer'#010+ + '8*2Anasm_Assemble using Nasm'#010+ '8*2Anasmobj_Assemble using Nasm'#010+ '3*2Anasm_Assemble using Nasm'#010+ '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+ '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+ - '3*2Anasmwin32_Win32 object file using Nasm'#010+ - '3*2Anasmwdosx_Win32/WDOSX ','object file using Nasm'#010+ + '3*2A','nasmwin32_Win32 object file using Nasm'#010+ + '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+ '3*2Anasmdarwin_macho32 object file using Nasm (experimental)'#010+ '3*2Awasm_Obj file using Wasm (Watcom)'#010+ '3*2Anasmobj_Obj file using Nasm'#010+ - '3*2Amasm_Obj file using Masm (Microsoft)'#010+ + '3*2Amasm_Obj file usi','ng Masm (Microsoft)'#010+ '3*2Atasm_Obj file using Tasm (Borland)'#010+ - '3*2Ael','f_ELF (Linux) using internal writer'#010+ + '3*2Aelf_ELF (Linux) using internal writer'#010+ '3*2Acoff_COFF (Go32v2) using internal writer'#010+ '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+ '3*2Ayasm_Assemble using Yasm (experimental)'#010+ - '4*2Aas_Assemble using GNU AS'#010+ + '4','*2Aas_Assemble using GNU AS'#010+ '4*2Agas_Assemble using GNU GAS'#010+ - '4*2Aas','-darwin_Assemble Darwin Mach-O using GNU GAS'#010+ + '4*2Aas-darwin_Assemble Darwin Mach-O using GNU GAS'#010+ '4*2Amasm_Win64 object file using ml64 (Microsoft)'#010+ '4*2Apecoff_PE-COFF (Win64) using internal writer'#010+ - '4*2Aelf_ELF (Linux-64bit) using internal writer'#010+ + '4*2Aelf_ELF (Linux-64bit) using',' internal writer'#010+ '4*2Ayasm_Assemble using Yasm (experimental)'#010+ - '4*2A','nasm_Assemble using Nasm (experimental)'#010+ + '4*2Anasm_Assemble using Nasm (experimental)'#010+ '4*2Anasmwin64_Assemble Win64 object file using Nasm (experimental)'#010+ - '4*2Anasmelf_Assemble Linux-64bit object file using Nasm (experimental)'+ - #010+ - '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm ','(exper'+ - 'imental)'#010+ + '4*2Anasmelf_Assemble Linux-64bit object file using Nasm (experimenta','l'+ + ')'#010+ + '4*2Anasmdarwin_Assemble darwin macho64 object file using Nasm (experim'+ + 'ental)'#010+ '6*2Aas_Unix o-file using GNU AS'#010+ '6*2Agas_GNU Motorola assembler'#010+ '6*2Amit_MIT Syntax (old GAS)'#010+ '6*2Amot_Standard Motorola assembler'#010+ '6*2Avasm_Use vasm to assemble'#010+ - 'A*2Aas_Assemble using GNU AS'#010+ + 'A*','2Aas_Assemble using GNU AS'#010+ 'P*2Aas_Assemble using GNU AS'#010+ - 'S*2Aas_As','semble using GNU AS'#010+ + 'S*2Aas_Assemble using GNU AS'#010+ 'Z*2Asdcc-sdasz80_Assemble using SDCC-SDASZ80'#010+ 'Z*2Az80asm_Assemble using z80asm'#010+ '**1b_Generate browser info'#010+ '**2bl_Generate local symbol info'#010+ - '**1B_Build all modules'#010+ + '**1B_Build all mo','dules'#010+ '**1C<x>_Code generation options:'#010+ - '**2C3_Turn on ieee error c','hecking for constants'#010+ + '**2C3_Turn on ieee error checking for constants'#010+ '**2Ca<x>_Select ABI; see fpc -i or fpc -ia for possible values'#010+ '**2Cb_Generate code for a big-endian variant of the target architectur'+ 'e'#010+ - '**2Cc<x>_Set default calling convention to <x>'#010+ - '**2CD_Create also dynamic library (n','ot supported)'#010+ + '**2Cc<x>_Set defau','lt calling convention to <x>'#010+ + '**2CD_Create also dynamic library (not supported)'#010+ '**2Ce_Compilation with emulated floating point opcodes'#010+ '**2CE_Generate FPU code which can raise exceptions'#010+ - '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+ - 'possible values'#010+ - '**2CF<x>_Minimal floating point co','nstant precision (default, 32, 64)'+ - #010+ + '**2Cf<x>_Select fpu instruction set to use; see fpc -i ','or fpc -if fo'+ + 'r possible values'#010+ + '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+ '**2Cg_Generate PIC code'#010+ '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+ 'ptionally [m] max heap size'#010+ - '**2Ci_IO-checking'#010+ + '**2Ci_IO-checking'#010, 'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+ - 'L*2Cl<x>_LLV','M code generation options'#010+ + 'L*2Cl<x>_LLVM code generation options'#010+ 'L*3Clflto_Enable Link-time optimisation (needed both when compiling un'+ 'its and programs/libraries)'#010+ - 'L*3Clfltonosystem_Disable LTO for the system unit (needed with at leas'+ - 't Xcode 10.2 and earlier due to linker bugs)'#010+ - 'L','*3Clv<x>_LLVM target version: Xcode-10.1, 7.0, 8.0, .., 10.0'#010+ + 'L*3Clfltonosystem_Disable LTO for the system unit (','needed with at le'+ + 'ast Xcode 10.2 and earlier due to linker bugs)'#010+ + 'L*3Clv<x>_LLVM target version: Xcode-10.1, 7.0, 8.0, .., 10.0'#010+ '**2Cn_Omit linking stage'#010+ 'P*2CN_Generate nil-pointer checks (AIX-only)'#010+ '**2Co_Check overflow of integer operations'#010+ - '**2CO_Check for possible overflow of integer operations'#010+ - '**2Cp<x>_S','elect instruction set; see fpc -i or fpc -ic for possible '+ - 'values'#010+ + '*','*2CO_Check for possible overflow of integer operations'#010+ + '**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possible va'+ + 'lues'#010+ '**2CP<x>=<y>_ packing settings'#010+ '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+ 'and 8'#010+ - '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NOR','M'+ - 'AL'#010+ + '**3','CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NOR'+ + 'MAL'#010+ '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+ ' 4, 8, 16 and 32'#010+ '**2Cr_Range checking'#010+ '**2CR_Verify object method call validity'#010+ - '**2Cs<n>_Set stack checking size to <n>'#010+ - '**2Ct_Stack checking (for testing only, see man','ual)'#010+ + '**2Cs<n>_Set stack che','cking size to <n>'#010+ + '**2Ct_Stack checking (for testing only, see manual)'#010+ '8*2CT<x>_Target-specific code generation options'#010+ '3*2CT<x>_Target-specific code generation options'#010+ '4*2CT<x>_Target-specific code generation options'#010+ - 'p*2CT<x>_Target-specific code generation options'#010+ - 'P*2CT<x>_Target-specific code generatio','n options'#010+ + 'p*2CT<x>_Target-specifi','c code generation options'#010+ + 'P*2CT<x>_Target-specific code generation options'#010+ 'J*2CT<x>_Target-specific code generation options'#010+ 'A*2CT<x>_Target-specific code generation options'#010+ - 'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+ - ' (AIX)'#010+ - 'P*3CTsmalltoc_ Generate smaller TOCs at the expense of ','execution spe'+ + 'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution sp','e'+ 'ed (AIX)'#010+ + 'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+ + ' (AIX)'#010+ 'J*3CTautogetterprefix=X_ Automatically create getters for properties '+ 'with prefix X (empty string disables)'#010+ - 'J*3CTautosetterprefix=X_ Automatically create setters for properties '+ - 'with prefix X (empty string disables)'#010+ - '8*','3CTcld_ Emit a CLD instruction before using the x8'+ - '6 string instructions'#010+ + 'J*3CTautosetterprefix=X_ Automatically creat','e setters for propertie'+ + 's with prefix X (empty string disables)'#010+ + '8*3CTcld_ Emit a CLD instruction before using the x86 '+ + 'string instructions'#010+ '3*3CTcld_ Emit a CLD instruction before using the x86 '+ + 'string instructio','ns'#010+ + '4*3CTcld_ Emit a CLD instruction before using the x86 '+ 'string instructions'#010+ - '4*3CTcld_ Emit a CLD instruction before using ','the x8'+ - '6 string instructions'#010+ '8*3CTfarprocspushoddbp_ Increment BP before pushing it in the pr'+ 'ologue of far functions'#010+ - 'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+ - 'de for initializing integer array constants'#010+ - 'J*3C','Tenumfieldinit_ Initialize enumeration fields in construct'+ - 'ors to enumtype(0), after calling inherited constructors'#010+ - 'J*3CTinitlocals_ Initialize local variables that trigger a JV'+ - 'M bytecode verification error if used uninitializ','ed (slows down code'+ + 'J*3CTcompactintarrayinit_ Generate smaller (but poten','tially slower) '+ + 'code for initializing integer array constants'#010+ + 'J*3CTenumfieldinit_ Initialize enumeration fields in constructor'+ + 's to enumtype(0), after calling inherited constructors'#010+ + 'J*3CTinitlocals_ Initialize local variables t','hat trigger a '+ + 'JVM bytecode verification error if used uninitialized (slows down code'+ ')'#010+ 'J*3CTlowercaseprocstart_ Lowercase the first character of procedure/f'+ 'unction/method names'#010+ - 'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+ - 'ble'#010+ + 'A*3CTthumbinterworking_ Generate Thumb interworking-safe code i','f pos'+ + 'sible'#010+ 'J*2Cv_Var/out parameter copy-out checking'#010+ - 'A*2CV<x>_Set',' section threadvar model to <x>'#010+ + 'A*2CV<x>_Set section threadvar model to <x>'#010+ '**2CX_Create also smartlinked library'#010+ '**1d<x>_Defines the symbol <x>'#010+ '**1D_Generate a DEF file'#010+ - '**2DD<x>_Set the date string returned by %DATE% to x, it is not checke'+ - 'd for being a valid date string'#010+ - '**2Dd<x>_Set',' description to <x>'#010+ + '**2DD<x>_Set the date string returned by %DATE% t','o x, it is not chec'+ + 'ked for being a valid date string'#010+ + '**2Dd<x>_Set description to <x>'#010+ '**2DT<x>_Set the time string returned by %TIME% to x, it is not checke'+ 'd for being a valid time string'#010+ '**2Dv<x>_Set DLL version to <x>'#010+ - '*O2Dw_PM application'#010+ + '*O2Dw_PM application'#010, '**1e<x>_Set path to executable'#010+ '**1E_Same as -Cn'#010+ - '**1fPIC_Same as -','Cg'#010+ + '**1fPIC_Same as -Cg'#010+ '**1F<x>_Set file names and paths:'#010+ '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+ 'sed'#010+ '**2Fc<x>_Set input codepage to <x>'#010+ - '**2FC<x>_Set RC compiler binary name to <x>'#010+ - '**2Fd_Disable the compiler'#039's internal directory ca','che'#010+ + '**2FC<x>_Set RC compiler bina','ry name to <x>'#010+ + '**2Fd_Disable the compiler'#039's internal directory cache'#010+ '**2FD<x>_Set the directory where to search for compiler utilities'#010+ '**2Fe<x>_Redirect error output to <x>'#010+ '**2FE<x>_Set exe/unit output path to <x>'#010+ - '**2Ff<x>_Add <x> to framework path (Darwin only), or set IDF path to <'+ - 'x> (Xtensa-FreeRTOS)'#010, + '**2Ff<x>_Add <x> to framew','ork path (Darwin only), or set IDF path to'+ + ' <x> (Xtensa-FreeRTOS)'#010+ '**2FF_Use fpcres as RC to RES compiler instead of windres or gorc'#010+ '**2Fi<x>_Add <x> to include path'#010+ '**2Fl<x>_Add <x> to library path'#010+ '**2FL<x>_Use <x> as dynamic linker'#010+ - '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+ - 'r'#010+ - '*','*2FM<x>_Set the directory where to search for unicode binary files'#010+ + '**2Fm<x>','_Load unicode conversion table from <x>.txt in the compiler '+ + 'dir'#010+ + '**2FM<x>_Set the directory where to search for unicode binary files'#010+ '**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+ '**2Fo<x>_Add <x> to object path'#010+ - '**2Fr<x>_Load error message file <x>'#010+ - '**2FR<x>_Set resource (.res) linker to <x>'#010, + '**2Fr<x>_Load e','rror message file <x>'#010+ + '**2FR<x>_Set resource (.res) linker to <x>'#010+ '**2Fu<x>_Add <x> to unit path'#010+ '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+ '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+ - '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+ - 'om <x>'#010+ - '*g1g_Generate',' debug information (default format for target)'#010+ + '**2Fw<x>_Load previously ','stored whole-program optimization feedback '+ + 'from <x>'#010+ + '*g1g_Generate debug information (default format for target)'#010+ '*g2gc_Generate checks for pointers (experimental, only available on so'+ 'me targets, might generate false positive)'#010+ - '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+ - '*g2gl_Use line i','nfo unit (show more info with backtraces)'#010+ + '*g2gh_Use heapt','race unit (for memory leak/corruption debugging)'#010+ + '*g2gl_Use line info unit (show more info with backtraces)'#010+ '*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+ '*g2go<x>_Set debug information options'#010+ - '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+ - 'aks gdb < 6.5)'#010+ - '*g3gostabsabsin','cludes_ Store absolute/full include file paths in Sta'+ - 'bs'#010+ + '*g3godwarfsets_ Enable DWAR','F '#039'set'#039' type debug information (b'+ + 'reaks gdb < 6.5)'#010+ + '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+ + #010+ '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+ 'ame'#010+ - '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+ - '*g3godwarfomflinnum_ Generate line number information i','n OMF LINNUM '+ - 'records in MS LINK format in addition to the DWARF debug information ('+ - 'Open Watcom Debugger/Linker compatibility)'#010+ + '*g3godwarfcpp_ Simulate C++ debug information',' in DWARF'#010+ + '*g3godwarfomflinnum_ Generate line number information in OMF LINNUM re'+ + 'cords in MS LINK format in addition to the DWARF debug information (Op'+ + 'en Watcom Debugger/Linker compatibility)'#010+ '*g2gp_Preserve case in stabs symbol names'#010+ - '*g2gs_Generate Stabs debug information'#010+ - '*g2gt_Trash local variables (to d','etect uninitialized uses; multiple '+ - #039't'#039' changes the trashing value)'#010+ + '*g2gs_G','enerate Stabs debug information'#010+ + '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+ + 't'#039' changes the trashing value)'#010+ '*g2gv_Generates programs traceable with Valgrind'#010+ '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+ - '*g2gw2_Generate DWARFv2 debug information'#010+ - '*g2gw3_Generate DWARFv3 de','bug information'#010+ + '*g2','gw2_Generate DWARFv2 debug information'#010+ + '*g2gw3_Generate DWARFv3 debug information'#010+ '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+ '**1i_Information'#010+ '**2iD_Return compiler date'#010+ '**2iSO_Return compiler OS'#010+ - '**2iSP_Return compiler host processor'#010+ + '**2iSP_Return compiler host proc','essor'#010+ '**2iTO_Return target OS'#010+ '**2iTP_Return target processor'#010+ - '**2i','V_Return short compiler version'#010+ + '**2iV_Return short compiler version'#010+ '**2iW_Return full compiler version'#010+ '**2ia_Return list of supported ABI targets'#010+ '**2ib_Return the used code generation backend type'#010+ - '**2ic_Return list of supported CPU instruction sets'#010+ - '**2if_Return list of suppor','ted FPU instruction sets'#010+ + '**2ic_Return l','ist of supported CPU instruction sets'#010+ + '**2if_Return list of supported FPU instruction sets'#010+ '**2ii_Return list of supported inline assembler modes'#010+ '**2im_Return list of supported modeswitches'#010+ '**2io_Return list of supported optimizations'#010+ - '**2ir_Return list of recognized compiler and RTL features'#010+ - '**2it_Return l','ist of supported targets'#010+ + '**2ir_R','eturn list of recognized compiler and RTL features'#010+ + '**2it_Return list of supported targets'#010+ '**2iu_Return list of supported microcontroller types'#010+ '**2iw_Return list of supported whole program optimizations'#010+ '**1I<x>_Add <x> to include path'#010+ - '**1k<x>_Pass <x> to the linker'#010+ + '**1k<x','>_Pass <x> to the linker'#010+ '**1l_Write logo'#010+ - '**1M<x>_Set language mod','e to <x> / enable modeswitch <x> (see option'+ - ' -im)'#010+ + '**1M<x>_Set language mode to <x> / enable modeswitch <x> (see option -'+ + 'im)'#010+ '**2Mfpc_Free Pascal dialect (default)'#010+ '**2Mobjfpc_FPC mode with Object Pascal support'#010+ '**2Mdelphi_Delphi 7 compatibility mode'#010+ - '**2Mtp_TP/BP 7.0 compatibility mode'#010+ - '**2Mmacpas_Macintosh Pascal di','alects compatibility mode'#010+ + '*','*2Mtp_TP/BP 7.0 compatibility mode'#010+ + '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+ '**2Miso_ISO 7185 mode'#010+ '**2Mextendedpascal_ISO 10206 mode'#010+ '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+ - '**2*_Each mode (as listed above) enables its default set of modeswitch'+ - 'es.'#010+ - '**2*_Other modeswitches a','re disabled and need to be enabled one by a'+ - 'nother.'#010+ + '**2*_Each mode (as listed above) e','nables its default set of modeswit'+ + 'ches.'#010+ + '**2*_Other modeswitches are disabled and need to be enabled one by ano'+ + 'ther.'#010+ '**1M<x>-_Disable modeswitch <x> (see option -im)'#010+ '**1n_Do not read the default config files'#010+ - '**1o<x>_Change the name of the executable produced to <x>'#010+ + '**1o<x>_Change the name of the ex','ecutable produced to <x>'#010+ '**1O<x>_Optimizations:'#010+ - '**2O-_Disable opt','imizations'#010+ + '**2O-_Disable optimizations'#010+ '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+ '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+ - '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+ - '**2O4_Level 4 optimizations (-O3 + optimizations which might',' have un'+ - 'expected side effects)'#010+ + '**2O3_Level 3 optimizations (-O2 + slow optimizati','ons)'#010+ + '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+ + 'pected side effects)'#010+ '**2Oa<x>=<y>_Set alignment'#010+ '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+ 'r possible values'#010+ - '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+ - 'ible values'#010+ - '**2OW<x>_Gen','erate whole-program optimization feedback for optimizati'+ - 'on <x>; see fpc -i or fpc -iw for possible values'#010+ - '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+ - ' for possible values'#010+ + '**2Op<x>_Set target cpu for o','ptimizing; see fpc -i or fpc -ic for po'+ + 'ssible values'#010+ + '**2OW<x>_Generate whole-program optimization feedback for optimization'+ + ' <x>; see fpc -i or fpc -iw for possible values'#010+ + '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -i', + 'w for possible values'#010+ '**2Os_Optimize for size rather than speed'#010+ - '*','*1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+ + '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+ 'F*1P<x>_Target CPU / compiler related options:'#010+ 'F*2PB_Show default compiler binary'#010+ 'F*2PP_Show default target cpu'#010+ - 'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mips', - 'el,powerpc,powerpc64,sparc,x86_64)'#010+ + 'F*2P','<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mip'+ + 'sel,powerpc,powerpc64,sparc,x86_64)'#010+ '**1R<x>_Assembler reading style:'#010+ '**2Rdefault_Use default assembler for target'#010+ '3*2Ratt_Read AT&T style assembler'#010+ - '3*2Rintel_Read Intel style assembler'#010+ + '3*2Rintel_Read Intel style a','ssembler'#010+ '4*2Ratt_Read AT&T style assembler'#010+ - '4*2Rintel_Read Intel s','tyle assembler'#010+ + '4*2Rintel_Read Intel style assembler'#010+ '8*2Ratt_Read AT&T style assembler'#010+ '8*2Rintel_Read Intel style assembler'#010+ '6*2RMOT_Read Motorola style assembler'#010+ '**1S<x>_Syntax options:'#010+ '**2S2_Same as -Mobjfpc'#010+ - '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+ - '**2Sa_Turn on assert','ions'#010+ + '**2S','c_Support operators like C (*=,+=,/= and -=)'#010+ + '**2Sa_Turn on assertions'#010+ '**2Sd_Same as -Mdelphi'#010+ '**2Se<x>_Error options. <x> is a combination of the following:'#010+ '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+ - '**3*_w : Compiler also halts after warnings'#010+ + '**3*_w : Compiler also',' halts after warnings'#010+ '**3*_n : Compiler also halts after notes'#010+ - '**','3*_h : Compiler also halts after hints'#010+ + '**3*_h : Compiler also halts after hints'#010+ '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+ 'ir for possible values)'#010+ - '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+ - '**2Sh_Use reference counted strings (ansistring ','by default) instead '+ - 'of shortstrings'#010+ + '**2Sg_Enable LABEL and GOTO (default in -M','tp and -Mdelphi)'#010+ + '**2Sh_Use reference counted strings (ansistring by default) instead of'+ + ' shortstrings'#010+ '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+ '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+ - '**2Sk_Load fpcylix unit'#010+ + '**2','Sk_Load fpcylix unit'#010+ '**2SI<x>_Set interface style to <x>'#010+ - '**3SIcom','_COM compatible interface (default)'#010+ + '**3SIcom_COM compatible interface (default)'#010+ '**3SIcorba_CORBA compatible interface'#010+ '**2sT_Generate script only to link on target'#010+ '**2Sm_Support macros like C (global)'#010+ - '**2So_Same as -Mtp'#010+ + '**2So_Same as -Mtp'#010, '**2Sr_Transparent file names in ISO mode'#010+ - '**2Ss_Constructor name m','ust be init (destructor must be done)'#010+ + '**2Ss_Constructor name must be init (destructor must be done)'#010+ '**2Sv_Support vector processing (use CPU vector extensions if availabl'+ 'e)'#010+ - '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+ + '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)',#010+ '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+ - '**1s_Do no','t call assembler and linker'#010+ + '**1s_Do not call assembler and linker'#010+ '**2sh_Generate script to link on host'#010+ '**2st_Generate script to assemble and link on target'#010+ '**2sr_Skip register allocation phase (use with -alr)'#010+ - '**1T<x>_Target operating system:'#010+ + '**1','T<x>_Target operating system:'#010+ '3*2Tandroid_Android'#010+ '3*2Taros_AROS'#010+ - '3','*2Tbeos_BeOS'#010+ + '3*2Tbeos_BeOS'#010+ '3*2Tdarwin_Darwin/Mac OS X'#010+ '3*2Tembedded_Embedded'#010+ '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+ '3*2Tfreebsd_FreeBSD'#010+ - '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+ + '3*2Tgo32v2_Version 2 of DJ Delorie DOS exte','nder'#010+ '3*2Thaiku_Haiku'#010+ - '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3','.2+ (older versions: -Td'+ - 'arwin)'#010+ + '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+ + 'win)'#010+ '3*2Tlinux_Linux'#010+ '3*2Tnativent_Native NT API (experimental)'#010+ '3*2Tnetbsd_NetBSD'#010+ '3*2Tnetware_Novell Netware Module (clib)'#010+ - '3*2Tnetwlibc_Novell Netware Module (libc)'#010+ + '3*2Tnetwlibc_Novell Netware',' Module (libc)'#010+ '3*2Topenbsd_OpenBSD'#010+ '3*2Tos2_OS/2 / eComStation'#010+ - '3*2','Tsymbian_Symbian OS'#010+ + '3*2Tsymbian_Symbian OS'#010+ '3*2Tsolaris_Solaris'#010+ '3*2Twatcom_Watcom compatible DOS extender'#010+ '3*2Twdosx_WDOSX DOS extender'#010+ '3*2Twin32_Windows 32 Bit'#010+ '3*2Twince_Windows CE'#010+ - '4*2Tandroid_Android'#010+ + '4*2Tandroid_Androi','d'#010+ '4*2Taros_AROS'#010+ '4*2Tdarwin_Darwin/Mac OS X'#010+ - '4*2Tdragonfly_DragonFl','y BSD'#010+ + '4*2Tdragonfly_DragonFly BSD'#010+ '4*2Tembedded_Embedded'#010+ '4*2Tfreebsd_FreeBSD'#010+ '4*2Thaiku_Haiku'#010+ @@ -1793,19 +1796,19 @@ const msgtxt : array[0..000362,1..240] of char=( '4*2Tnetbsd_NetBSD'#010+ '4*2Topenbsd_OpenBSD'#010+ '4*2Tsolaris_Solaris'#010+ - '4*2Twin64_Win64 (64 bit Windows systems)'#010+ + '4*2Twin','64_Win64 (64 bit Windows systems)'#010+ '6*2Tamiga_Commodore Amiga'#010+ - '6*2Ta','tari_Atari ST/STe/TT'#010+ + '6*2Tatari_Atari ST/STe/TT'#010+ '6*2Tembedded_Embedded'#010+ '6*2Tlinux_Linux'#010+ '6*2Tnetbsd_NetBSD'#010+ '6*2Tmacosclassic_Classic Mac OS'#010+ '6*2Tpalmos_PalmOS'#010+ '6*2Tsinclairql_Sinclair QL'#010+ - '8*2Tembedded_Embedded'#010+ + '8*2Tembedded_Embedded',#010+ '8*2Tmsdos_MS-DOS (and compatible)'#010+ '8*2Twin16_Windows 16 Bit'#010+ - 'A*2Ta','ndroid_Android'#010+ + 'A*2Tandroid_Android'#010+ 'A*2Taros_AROS'#010+ 'A*2Tembedded_Embedded'#010+ 'A*2Tfreertos_FreeRTOS'#010+ @@ -1814,10 +1817,10 @@ const msgtxt : array[0..000362,1..240] of char=( 'A*2Tlinux_Linux'#010+ 'A*2Tnds_Nintendo DS'#010+ 'A*2Tnetbsd_NetBSD'#010+ - 'A*2Tpalmos_PalmOS'#010+ + 'A*2Tpalmos_','PalmOS'#010+ 'A*2Tsymbian_Symbian'#010+ 'A*2Twince_Windows CE'#010+ - 'a*2Tandroid_Andro','id'#010+ + 'a*2Tandroid_Android'#010+ 'a*2Tdarwin_Darwin/Mac OS X'#010+ 'a*2Tios_iOS'#010+ 'a*2Tlinux_Linux'#010+ @@ -1827,11 +1830,11 @@ const msgtxt : array[0..000362,1..240] of char=( 'm*2Tandroid_Android'#010+ 'm*2Tembedded_Embedded'#010+ 'm*2Tlinux_Linux'#010+ - 'M*2Tembedded_Embedded'#010+ + 'M*2T','embedded_Embedded'#010+ 'M*2Tlinux_Linux'#010+ 'P*2Taix_AIX'#010+ 'P*2Tamiga_AmigaOS'#010+ - 'P','*2Tdarwin_Darwin/Mac OS X'#010+ + 'P*2Tdarwin_Darwin/Mac OS X'#010+ 'P*2Tembedded_Embedded'#010+ 'P*2Tlinux_Linux'#010+ 'P*2Tmacosclassic_Classic Mac OS'#010+ @@ -1839,11 +1842,11 @@ const msgtxt : array[0..000362,1..240] of char=( 'P*2Tnetbsd_NetBSD'#010+ 'P*2Twii_Wii'#010+ 'p*2Taix_AIX'#010+ - 'p*2Tdarwin_Darwin/Mac OS X'#010+ + 'p*2Tdarwin_Darwin','/Mac OS X'#010+ 'p*2Tembedded_Embedded'#010+ 'p*2Tlinux_Linux'#010+ 'R*2Tlinux_Linux'#010+ - 'R','*2Tembedded_Embedded'#010+ + 'R*2Tembedded_Embedded'#010+ 'r*2Tlinux_Linux'#010+ 'r*2Tembedded_Embedded'#010+ 'S*2Tlinux_Linux'#010+ @@ -1851,161 +1854,166 @@ const msgtxt : array[0..000362,1..240] of char=( 's*2Tlinux_Linux'#010+ 'V*2Tembedded_Embedded'#010+ 'x*2Tembedded_Embedded'#010+ - 'x*2Tfreertos_FreeRTOS'#010+ + 'x*2Tfreertos_FreeRTO','S'#010+ 'x*2Tlinux_Linux'#010+ 'Z*2Tembedded_Embedded'#010+ - 'Z*2Tzxspectrum_ZX Spectru','m'#010+ + 'Z*2Tzxspectrum_ZX Spectrum'#010+ 'Z*2Tmsxdos_MSX-DOS'#010+ '**1u<x>_Undefines the symbol <x>'#010+ '**1U_Unit options:'#010+ '**2Un_Do not check where the unit name matches the file name'#010+ - '**2Ur_Generate release unit files (never automatically recompiled)'#010+ + '**2Ur_Generate release unit files (never ','automatically recompiled)'#010+ '**2Us_Compile a system unit'#010+ - '**1v<x>_Be ','verbose. <x> is a combination of the following letters:'#010+ + '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+ '**2*_e : Show errors (default) 0 : Show nothing (except errors)'#010+ - '**2*_w : Show warnings u : Show unit info'#010+ - '**2*_n : Show notes t : Show tried/used f','iles'#010+ + '**2*_w : Show warnings u : Show uni','t info'#010+ + '**2*_n : Show notes t : Show tried/used files'#010+ '**2*_h : Show hints c : Show conditionals'#010+ '**2*_i : Show general info d : Show debug info'#010+ - '**2*_l : Show linenumbers r : Rhide/GCC compatibility mode'#010+ - '**2*_s : Show time stamps q : Show mes','sage numbers'#010+ + '**2*_l : Show linenumbers r : Rhide/GCC com','patibility mod'+ + 'e'#010+ + '**2*_s : Show time stamps q : Show message numbers'#010+ '**2*_a : Show everything x : Show info about invoked tools'+ #010+ '**2*_b : Write file names messages p : Write tree.log with parse tre'+ 'e'#010+ - '**2*_ with full path v : Write fpcdebug.txt with'#010+ - '**2*_z : Write outp','ut to stderr lots of debugging info'#010+ + '**2*_ with full ','path v : Write fpcdebug.txt with'#010+ + '**2*_z : Write output to stderr lots of debugging info'#010+ '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+ 'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+ - 'or version)'#010+ + 'or version',')'#010+ '**1W<x>_Target-specific options (targets)'#010+ - '3*2WA_Specify native ','type application (Windows)'#010+ + '3*2WA_Specify native type application (Windows)'#010+ '4*2WA_Specify native type application (Windows)'#010+ 'A*2WA_Specify native type application (Windows)'#010+ - '3*2Wb_Create a bundle instead of a library (Darwin)'#010+ + '3*2Wb_Create a bundle instead of a library (Darwin)'#010, 'P*2Wb_Create a bundle instead of a library (Darwin)'#010+ - 'p*2Wb_Create ','a bundle instead of a library (Darwin)'#010+ + 'p*2Wb_Create a bundle instead of a library (Darwin)'#010+ 'a*2Wb_Create a bundle instead of a library (Darwin)'#010+ 'A*2Wb_Create a bundle instead of a library (Darwin)'#010+ - '4*2Wb_Create a bundle instead of a library (Darwin)'#010+ - '3*2WB_Create a relocatable image (Windows, Sy','mbian)'#010+ + '4*2Wb_Create a bundle instead of',' a library (Darwin)'#010+ + '3*2WB_Create a relocatable image (Windows, Symbian)'#010+ '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+ '4*2WB_Create a relocatable image (Windows)'#010+ '4*2WB<x>_Set image base to <x> (Windows)'#010+ - 'A*2WB_Create a relocatable image (Windows, Symbian)'#010+ - 'A*2WB<x>_Set image base to <x> (Windows, Symbia','n)'#010+ + 'A*2WB_Create a relocatable image (','Windows, Symbian)'#010+ + 'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+ 'Z*2WB<x>_Set image base to <x> (ZX Spectrum)'#010+ '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+ '4*2WC_Specify console type application (Windows)'#010+ - 'A*2WC_Specify console type application (Windows)'#010+ - 'P*2WC_Specify console type applica','tion (Classic Mac OS)'#010+ + 'A*2WC_Specify cons','ole type application (Windows)'#010+ + 'P*2WC_Specify console type application (Classic Mac OS)'#010+ '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+ '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+ - 'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+ - '3*2We_Use external resources (Da','rwin)'#010+ + 'A*2WD_Use DEFFILE to export f','unctions of DLL or EXE (Windows)'#010+ + '3*2We_Use external resources (Darwin)'#010+ '4*2We_Use external resources (Darwin)'#010+ 'a*2We_Use external resources (Darwin)'#010+ 'A*2We_Use external resources (Darwin)'#010+ 'P*2We_Use external resources (Darwin)'#010+ - 'p*2We_Use external resources (Darwin)'#010+ - '3*2WF_Specify full-screen type application (','EMX, OS/2)'#010+ + 'p*2We_Use externa','l resources (Darwin)'#010+ + '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+ '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+ '4*2WG_Specify graphic type application (Windows)'#010+ 'A*2WG_Specify graphic type application (Windows)'#010+ - 'P*2WG_Specify graphic type application (Classic Mac OS)'#010+ - '3*2Wi_Use inter','nal resources (Darwin)'#010+ + 'P*2WG_','Specify graphic type application (Classic Mac OS)'#010+ + '3*2Wi_Use internal resources (Darwin)'#010+ '4*2Wi_Use internal resources (Darwin)'#010+ 'a*2Wi_Use internal resources (Darwin)'#010+ 'A*2Wi_Use internal resources (Darwin)'#010+ - 'P*2Wi_Use internal resources (Darwin)'#010+ + 'P*2Wi_Use internal resources (Darwin)'#010, 'p*2Wi_Use internal resources (Darwin)'#010+ - '3*2WI_Turn on/off the usage',' of import sections (Windows)'#010+ + '3*2WI_Turn on/off the usage of import sections (Windows)'#010+ '4*2WI_Turn on/off the usage of import sections (Windows)'#010+ 'A*2WI_Turn on/off the usage of import sections (Windows)'#010+ - '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+ - 'e segment)'#010+ - '8*2Wm<x>_Set me','mory model'#010+ + '8*2Wh_Use huge code for units (','ignored for models with CODE in a uni'+ + 'que segment)'#010+ + '8*2Wm<x>_Set memory model'#010+ '8*3WmTiny_Tiny memory model'#010+ '8*3WmSmall_Small memory model (default)'#010+ '8*3WmMedium_Medium memory model'#010+ '8*3WmCompact_Compact memory model'#010+ - '8*3WmLarge_Large memory model'#010+ + '8*3WmLarge_Large memory model'#010, '8*3WmHuge_Huge memory model'#010+ - '3*2WM<x>_Minimum Mac OS X deployment ','version: 10.4, 10.5.1, ... (Dar'+ - 'win)'#010+ - '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+ + '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+ 'n)'#010+ - 'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+ + '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+ 'n)'#010+ - 'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1',', ... (Dar'+ + 'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (D','ar'+ 'win)'#010+ + 'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+ + 'n)'#010+ '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+ '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+ - 'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+ - 'A*2Wp<x>_Specif','y the controller type; see fpc -i or fpc -iu for poss'+ - 'ible values'#010+ - 'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ + 'A*2WN_Do not generat','e relocation code, needed for debugging (Windows'+ + ')'#010+ + 'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ 'le values'#010+ - 'R*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ + 'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ 'le values'#010+ - 'V*2Wp<x>_Specif','y the controller type; see fpc -i or fpc -iu for poss'+ + 'R*2Wp<x>_Specify the controlle','r type; see fpc -i or fpc -iu for poss'+ 'ible values'#010+ + 'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ + 'le values'#010+ 'x*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+ 'le values'#010+ - '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+ - '4*2WP<x>_Minimum iOS deplo','yment version: 8.0, 8.0.2, ... (iphonesim)'+ + '3*2WP<x>_Minimum iOS deploymen','t version: 3.0, 5.0.1, ... (iphonesim)'+ #010+ + '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+ 'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+ - 'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+ + 'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010, '3*2WR_Generate relocation code (Windows)'#010+ - '4*2WR_Generate relocatio','n code (Windows)'#010+ + '4*2WR_Generate relocation code (Windows)'#010+ 'A*2WR_Generate relocation code (Windows)'#010+ '8*2Wt<x>_Set the target executable format'#010+ '8*3Wtexe_Create a DOS .EXE file (default)'#010+ - '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+ - 'P*2WT_Specify MPW tool type applicati','on (Classic Mac OS)'#010+ + '8*3Wtcom_Create a DOS .COM file (','requires tiny memory model)'#010+ + 'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+ '6*2WQ<x>_Set executable metadata format (Sinclair QL)'#010+ '6*3WQqhdr_Set metadata to QDOS File Header style (default)'#010+ '6*3WQxtcc_Set metadata to XTcc style'#010+ - '**2WX_Enable executable stack (Linux)'#010+ + '**2WX','_Enable executable stack (Linux)'#010+ '**1X_Executable options:'#010+ - '**2X9_G','enerate linkerscript for GNU Binutils ld older than version 2'+ - '.19.1 (Linux)'#010+ + '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+ + '9.1 (Linux)'#010+ '**2Xa_Generate code which allows to use more than 2 GB static data on '+ '64 Bit targets (Linux)'#010+ - '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+ - 'ux',')'#010+ + '**2Xc_P','ass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+ + 'inux)'#010+ '**2Xd_Do not search default library path (sometimes required for cross'+ '-compiling when not using -XR)'#010+ '**2Xe_Use external linker'#010+ - '**2Xf_Substitute pthread library name for linking (BSD)'#010+ - '**2Xg_Create debuginfo in a separate file and add a deb','uglink sectio'+ - 'n to executable'#010+ + '**2Xf_Substitute pthread library name for link','ing (BSD)'#010+ + '**2Xg_Create debuginfo in a separate file and add a debuglink section '+ + 'to executable'#010+ '**2XD_Try to link units dynamically (defines FPC_LINK_DYNAMIC)'#010+ '**2Xi_Use internal linker'#010+ - 'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case clang is called clang-'+ - '7)'#010+ - '**2XLA_Define library substitutions for link','ing'#010+ + 'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case clan','g is called clan'+ + 'g-7)'#010+ + '**2XLA_Define library substitutions for linking'#010+ '**2XLO_Define order of library linking'#010+ '**2XLD_Exclude default order of standard libraries'#010+ '**2Xm_Generate link map'#010+ - '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+ - 's '#039'main'#039')'#010+ - '**2Xn_Use target system native linker instead of G','NU ld (Solaris, AI'+ - 'X)'#010+ + '**2XM<x>_Set the name of the '#039'main'#039' program routine (defa','ult'+ + ' is '#039'main'#039')'#010+ + '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+ + #010+ 'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+ '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+ - '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+ - 'ile, see the ld manual for mor','e information) (BeOS, Linux)'#010+ + '**2Xr<x>_Set the linker'#039's rlink','-path to <x> (needed for cross co'+ + 'mpile, see the ld manual for more information) (BeOS, Linux)'#010+ '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+ ', Linux, Mac OS, Solaris)'#010+ '**2Xs_Strip all symbols from executable'#010+ - '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+ - '**2Xt','_Link with static libraries (-static is passed to linker)'#010+ + '**2XS_Try ','to link units statically (default, defines FPC_LINK_STATIC'+ + ')'#010+ + '**2Xt_Link with static libraries (-static is passed to linker)'#010+ + '**2Xu_Generate executable in UF2 format (embedded targets only)'#010+ '**2Xv_Generate table for Virtual Entry calls'#010+ - '**2XV_Use VLink as external linker (default on Amiga, MorphOS)'#010+ + '**2XV_U','se VLink as external linker (default on Amiga, MorphOS)'+ + #010+ '**2XX_Try to smartlink units (defines FPC_LINK_SMART)'#010+ - '**','1*_'#010+ + '**1*_'#010+ '**1?_Show this help'#010+ '**1h_Shows this help without waiting' ); diff --git a/avx512-0037785/compiler/nadd.pas b/avx512-0037785/compiler/nadd.pas index b7ba6594fc..6c49f126e9 100644 --- a/avx512-0037785/compiler/nadd.pas +++ b/avx512-0037785/compiler/nadd.pas @@ -575,7 +575,7 @@ implementation var - t,vl,hp,lefttarget,righttarget, hp2: tnode; + t,vl,lefttarget,righttarget: tnode; lt,rt : tnodetype; hdef, rd,ld , inttype: tdef; @@ -3823,7 +3823,6 @@ implementation function taddnode.first_add64bitint: tnode; var procname: string[31]; - temp: tnode; power: longint; begin result := nil; diff --git a/avx512-0037785/compiler/nbas.pas b/avx512-0037785/compiler/nbas.pas index d9047f1157..308c643c09 100644 --- a/avx512-0037785/compiler/nbas.pas +++ b/avx512-0037785/compiler/nbas.pas @@ -706,8 +706,10 @@ implementation function tblocknode.simplify(forinline : boolean): tnode; +{$ifdef break_inlining} var a : array[0..3] of tstatementnode; +{$endif break_inlining} begin result := nil; { Warning: never replace a blocknode with another node type, @@ -1023,8 +1025,8 @@ implementation if segment <> NR_NO then Result := gas_regname(segment) + ':' else - Result := ''; {$endif defined(x86)} + Result := ''; if Assigned(symbol) then begin diff --git a/avx512-0037785/compiler/ncal.pas b/avx512-0037785/compiler/ncal.pas index c1efca2a37..4bf6208858 100644 --- a/avx512-0037785/compiler/ncal.pas +++ b/avx512-0037785/compiler/ncal.pas @@ -928,7 +928,10 @@ implementation reused above) } left:=ctemprefnode.create(paratemp); end; + { add the finish statements to the call cleanup block } addstatement(finistat,ctempdeletenode.create(paratemp)); + aktcallnode.add_done_statement(finiblock); + firstpass(fparainit); firstpass(left); end; diff --git a/avx512-0037785/compiler/ncginl.pas b/avx512-0037785/compiler/ncginl.pas index 08f0245681..b91cc6a6ac 100644 --- a/avx512-0037785/compiler/ncginl.pas +++ b/avx512-0037785/compiler/ncginl.pas @@ -406,7 +406,6 @@ implementation hregisterhi, {$endif not cpu64bitalu and not cpuhighleveltarget} hregister : tregister; - hloc: tlocation; begin { set defaults } addconstant:=true; diff --git a/avx512-0037785/compiler/ncgvmt.pas b/avx512-0037785/compiler/ncgvmt.pas index 2353ce7bc9..e887deea75 100644 --- a/avx512-0037785/compiler/ncgvmt.pas +++ b/avx512-0037785/compiler/ncgvmt.pas @@ -708,7 +708,7 @@ implementation while realintfdef.is_unique_objpasdef do realintfdef:=realintfdef.childof; - tmpstr:=_class.objname^+'_$_'+realintfdef.objname^+'_$_'+tostr(i)+'_$_'+pd.mangledname; + tmpstr:=_class.objname^+'_$_'+make_mangledname('',realintfdef.owner,'')+'_$$_'+realintfdef.objname^+'_$_'+tostr(i)+'_$_'+pd.mangledname; if length(tmpstr)>100 then begin crc:=0; diff --git a/avx512-0037785/compiler/ncnv.pas b/avx512-0037785/compiler/ncnv.pas index 20942a4c0c..4a58772252 100644 --- a/avx512-0037785/compiler/ncnv.pas +++ b/avx512-0037785/compiler/ncnv.pas @@ -2947,7 +2947,7 @@ implementation end; notn: result:=docheckremoveinttypeconvs(tunarynode(n).left); - addn,muln,divn,modn,andn: + addn,muln,divn,modn,andn,shln: begin if n.nodetype in [divn,modn] then gotdivmod:=true; @@ -2986,7 +2986,7 @@ implementation tempnode: ttempcreatenode; begin case n.nodetype of - subn,addn,muln,divn,modn,xorn,andn,orn: + subn,addn,muln,divn,modn,xorn,andn,orn,shln: begin exclude(n.flags,nf_internal); if not forceunsigned and @@ -3341,20 +3341,20 @@ 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]) and + (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit,s32bit,u32bit],int64(low(longint)),high(cardinal)) then doremoveinttypeconvs(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]) and + (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit],int64(low(smallint)),high(word)) then doremoveinttypeconvs(left,generrordef,not foundsint,s16inttype,u16inttype); {$endif defined(cpu16bitalu)} {$if defined(cpu8bitalu)} if (resultdef.size<left.resultdef.size) and is_integer(left.resultdef) and - (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn]) and + (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit],int64(low(shortint)),high(byte)) then doremoveinttypeconvs(left,generrordef,not foundsint,s8inttype,u8inttype); {$endif defined(cpu8bitalu)} diff --git a/avx512-0037785/compiler/ncon.pas b/avx512-0037785/compiler/ncon.pas index dabb8fac44..048624d664 100644 --- a/avx512-0037785/compiler/ncon.pas +++ b/avx512-0037785/compiler/ncon.pas @@ -655,7 +655,7 @@ implementation resultdef:=typedef; { only do range checking when explicitly asked for it and if the type can be range checked, see tests/tbs/tb0539.pp } - if (resultdef.typ in [orddef,enumdef]) then + if (resultdef.typ in [orddef,enumdef]) and not(nf_generic_para in flags) then adaptrange(resultdef,value,nf_internal in flags,not rangecheck,rangecheck) end; diff --git a/avx512-0037785/compiler/nflw.pas b/avx512-0037785/compiler/nflw.pas index 527484385a..5f6ec1b20e 100644 --- a/avx512-0037785/compiler/nflw.pas +++ b/avx512-0037785/compiler/nflw.pas @@ -244,8 +244,9 @@ interface function pass_1 : tnode;override; function simplify(forinline:boolean): tnode;override; protected - function dogetcopy: tnode;override; procedure adjust_estimated_stack_size; virtual; + public + function dogetcopy: tnode;override; end; ttryfinallynodeclass = class of ttryfinallynode; @@ -1557,14 +1558,14 @@ implementation function tifnode.internalsimplify(warn: boolean) : tnode; +{$if defined(i386) or defined(x86_64) or defined(xtensa)} var thenstmnt, elsestmnt: tnode; in_nr: tinlinenumber; paratype: tdef; +{$endif} begin result:=nil; - elsestmnt:=nil; - in_nr:=Default(tinlinenumber); { optimize constant expressions } if (left.nodetype=ordconstn) then begin @@ -1606,6 +1607,8 @@ implementation into appropriate min/max intrinsics } + elsestmnt:=nil; + in_nr:=Default(tinlinenumber); if (cs_opt_level2 in current_settings.optimizerswitches) and (left.nodetype in [gtn,gten,ltn,lten]) and IsSingleStatement(right,thenstmnt) and ((t1=nil) or IsSingleStatement(t1,elsestmnt)) and @@ -2722,6 +2725,13 @@ implementation result:=right; right:=nil; end; + { if the finally block contains no code, we can kill + it and just return the try part } + if has_no_code(right) and not(assigned(third)) and not(implicitframe) then + begin + result:=left; + left:=nil; + end; end; diff --git a/avx512-0037785/compiler/ngtcon.pas b/avx512-0037785/compiler/ngtcon.pas index 2158670d82..f08ec07c21 100644 --- a/avx512-0037785/compiler/ngtcon.pas +++ b/avx512-0037785/compiler/ngtcon.pas @@ -150,7 +150,7 @@ uses defutil,defcmp, { pass 1 } htypechk,procinfo, - nmem,ncnv,ninl,ncon,nld, + nmem,ncnv,ninl,ncon,nld,nadd, { parser specific stuff } pbase,pexpr, { codegen } @@ -826,7 +826,7 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis { maybe pchar ? } else if is_char(def.pointeddef) and - (node.nodetype<>addrn) then + ((node.nodetype=stringconstn) or is_constcharnode(node)) then begin { create a tcb for the string data (it's placed in a separate asmlist) } @@ -875,7 +875,7 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis { maybe pwidechar ? } else if is_widechar(def.pointeddef) and - (node.nodetype<>addrn) then + (node.nodetype in [stringconstn,ordconstn]) then begin if (node.nodetype in [stringconstn,ordconstn]) then begin @@ -912,13 +912,13 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis Message(parser_e_illegal_expression); end else - if (node.nodetype=addrn) or + if (node.nodetype in [addrn,addn,subn]) or is_proc2procvar_load(node,pd) then begin { insert typeconv } inserttypeconv(node,def); hp:=node; - while assigned(hp) and (hp.nodetype in [addrn,typeconvn,subscriptn,vecn]) do + while assigned(hp) and (hp.nodetype in [addrn,typeconvn,subscriptn,vecn,addn,subn]) do hp:=tunarynode(hp).left; if (hp.nodetype=loadn) then begin @@ -927,6 +927,28 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis while assigned(hp) and (hp.nodetype<>loadn) do begin case hp.nodetype of + addn : + begin + if (is_constintnode(taddnode(hp).right) or + is_constenumnode(taddnode(hp).right) or + is_constcharnode(taddnode(hp).right) or + is_constboolnode(taddnode(hp).right)) and + is_pointer(taddnode(hp).left.resultdef) then + ftcb.queue_addn(tpointerdef(taddnode(hp).left.resultdef).pointeddef,get_ordinal_value(taddnode(hp).right)) + else + Message(parser_e_illegal_expression); + end; + subn : + begin + if (is_constintnode(taddnode(hp).right) or + is_constenumnode(taddnode(hp).right) or + is_constcharnode(taddnode(hp).right) or + is_constboolnode(taddnode(hp).right)) and + is_pointer(taddnode(hp).left.resultdef) then + ftcb.queue_subn(tpointerdef(taddnode(hp).left.resultdef).pointeddef,get_ordinal_value(taddnode(hp).right)) + else + Message(parser_e_illegal_expression); + end; vecn : begin if (is_constintnode(tvecnode(hp).right) or diff --git a/avx512-0037785/compiler/nmem.pas b/avx512-0037785/compiler/nmem.pas index c5920e5741..604009fbe7 100644 --- a/avx512-0037785/compiler/nmem.pas +++ b/avx512-0037785/compiler/nmem.pas @@ -938,6 +938,7 @@ implementation htype,elementdef,elementptrdef : tdef; newordtyp: tordtype; valid : boolean; + minvalue, maxvalue: Tconstexprint; begin result:=nil; typecheckpass(left); @@ -1051,7 +1052,25 @@ implementation and not is_64bit(right.resultdef) {$endif not cpu64bitaddr} then - newordtyp:=Torddef(right.resultdef).ordtype + begin + { in case of an integer type, we need a new type which covers declaration range and index range, + see tests/webtbs/tw38413.pp + + This matters only if we sign extend, if the type exceeds the sint range, we can fall back only + to the index type + } + if is_integer(right.resultdef) and ((torddef(right.resultdef).low<0) or (TConstExprInt(Tarraydef(left.resultdef).lowrange)<0)) then + begin + minvalue:=min(TConstExprInt(Tarraydef(left.resultdef).lowrange),torddef(right.resultdef).low); + maxvalue:=max(TConstExprInt(Tarraydef(left.resultdef).highrange),torddef(right.resultdef).high); + if maxvalue>torddef(sinttype).high then + newordtyp:=Torddef(right.resultdef).ordtype + else + newordtyp:=range_to_basetype(minvalue,maxvalue); + end + else + newordtyp:=Torddef(right.resultdef).ordtype; + end else newordtyp:=torddef(sizesinttype).ordtype; inserttypeconv(right,corddef.create(newordtyp, diff --git a/avx512-0037785/compiler/ogbase.pas b/avx512-0037785/compiler/ogbase.pas index 5ed0cf9f0a..543577bee5 100644 --- a/avx512-0037785/compiler/ogbase.pas +++ b/avx512-0037785/compiler/ogbase.pas @@ -59,6 +59,8 @@ interface RELOC_RELATIVE_5, { PIC } RELOC_GOTPCREL, + RELOC_GOTPCRELX, + RELOC_REX_GOTPCRELX, RELOC_PLT32, RELOC_TLSGD, RELOC_TPOFF, diff --git a/avx512-0037785/compiler/ogomf.pas b/avx512-0037785/compiler/ogomf.pas index a78ac903b7..4644e77caa 100644 --- a/avx512-0037785/compiler/ogomf.pas +++ b/avx512-0037785/compiler/ogomf.pas @@ -338,15 +338,15 @@ interface property DwarfUnifiedLogicalSegments: TFPHashObjectList read FExeUnifiedLogicalSegments; property Header: TMZExeHeader read FHeader; protected - procedure Load_Symbol(const aname:string);override; procedure DoRelocationFixup(objsec:TObjSection);override; procedure Order_ObjSectionList(ObjSectionList : TFPObjectList;const aPattern:string);override; - procedure MemPos_ExeSection(const aname:string);override; - procedure MemPos_EndExeSection;override; function writeData:boolean;override; public constructor create;override; destructor destroy;override; + procedure Load_Symbol(const aname:string);override; + procedure MemPos_EndExeSection;override; + procedure MemPos_ExeSection(const aname:string);override; property MZFlatContentSection: TMZExeSection read GetMZFlatContentSection; end; @@ -1520,7 +1520,6 @@ implementation RawRecord: TOmfRawRecord; i,idx: Integer; objsym: TObjSymbol; - ExternalNameElem: TOmfExternalNameElement; ExtDefRec: TOmfRecord_EXTDEF; begin ExtNames:=TFPHashObjectList.Create; @@ -1532,7 +1531,7 @@ implementation objsym:=TObjSymbol(Data.ObjSymbolList[i]); if objsym.bind=AB_EXTERNAL then begin - ExternalNameElem:=TOmfExternalNameElement.Create(ExtNames,objsym.Name); + TOmfExternalNameElement.Create(ExtNames,objsym.Name); objsym.symidx:=idx; Inc(idx); end; @@ -1567,7 +1566,6 @@ implementation SegDef: TOmfRecord_SEGDEF; GrpDef: TOmfRecord_GRPDEF; nsections,ngroups: Integer; - objsym: TObjSymbol; begin { calc amount of sections we have and set their index, starting with 1 } nsections:=1; @@ -3157,9 +3155,6 @@ implementation i: Integer; ExeSec: TMZExeSection; ObjSec: TOmfObjSection; - StartDataPos: LongWord; - buf: array [0..1023] of byte; - bytesread: LongWord; begin Header.LoadableImageSize:=0; ExeSec:=MZFlatContentSection; @@ -3271,7 +3266,6 @@ implementation i: Integer; ExeSec: TMZExeSection; ObjSec: TOmfObjSection; - StartDataPos: LongWord; buf: array [0..1023] of byte; bytesread: LongWord; begin @@ -4102,9 +4096,8 @@ cleanup: function TNewExeEntryTable.GetSize: QWord; var - CurBundleStart, i: Integer; + CurBundleStart: Integer; CurBundleSize: Byte; - cp: TNewExeEntryPoint; begin Result:=0; CurBundleStart:=1; @@ -4417,7 +4410,7 @@ cleanup: var s: TSymStr; Separator: SizeInt; - SegName, SegClass: string; + {SegName,} SegClass: string; IsStack, IsBss: Boolean; begin { allow mixing initialized and uninitialized data in the same section @@ -4429,12 +4422,12 @@ cleanup: Separator:=Pos('||',s); if Separator>0 then begin - SegName:=Copy(s,1,Separator-1); + //SegName:=Copy(s,1,Separator-1); SegClass:=Copy(s,Separator+2,Length(s)-Separator-1); end else begin - SegName:=s; + //SegName:=s; SegClass:=''; end; { wlink recognizes the stack segment by the class name 'STACK' } diff --git a/avx512-0037785/compiler/options.pas b/avx512-0037785/compiler/options.pas index 627882ebb0..4bf2bf35f5 100644 --- a/avx512-0037785/compiler/options.pas +++ b/avx512-0037785/compiler/options.pas @@ -1830,6 +1830,7 @@ begin exclude(init_settings.globalswitches,cs_use_heaptrc); exclude(init_settings.globalswitches,cs_use_lineinfo); exclude(init_settings.localswitches,cs_checkpointer); + paratargetdbg:=dbg_none; localvartrashing := -1; end else @@ -2787,6 +2788,18 @@ begin end; 't' : include(init_settings.globalswitches,cs_link_staticflag); + 'u' : + begin + if target_info.system in systems_support_uf2 then + begin + if UnsetBool(More, j, opt, false) then + exclude(init_settings.globalswitches,cs_generate_uf2) + else + include(init_settings.globalswitches,cs_generate_uf2); + end + else + IgnoredPara('-Xu'); + end; 'v' : begin If UnsetBool(More, j, opt, false) then diff --git a/avx512-0037785/compiler/optloop.pas b/avx512-0037785/compiler/optloop.pas index 1c613453b7..8f25dfc38b 100644 --- a/avx512-0037785/compiler/optloop.pas +++ b/avx512-0037785/compiler/optloop.pas @@ -563,8 +563,6 @@ unit optloop; function OptimizeForLoop_iterforloops(var n: tnode; arg: pointer): foreachnoderesult; - var - hp : tnode; begin Result:=fen_false; if (n.nodetype=forn) and diff --git a/avx512-0037785/compiler/pdecsub.pas b/avx512-0037785/compiler/pdecsub.pas index f86f43f55d..b7ce1fda75 100644 --- a/avx512-0037785/compiler/pdecsub.pas +++ b/avx512-0037785/compiler/pdecsub.pas @@ -1133,61 +1133,70 @@ implementation if assigned(genericparams) then begin - include(pd.defoptions,df_generic); - { push the parameter symtable so that constraint definitions are added - there and not in the owner symtable } - symtablestack.push(pd.parast); - { register the parameters } - for i:=0 to genericparams.count-1 do + if potype=potype_constructor then begin - tsym(genericparams[i]).register_sym; - if tsym(genericparams[i]).typ=typesym then - tstoreddef(ttypesym(genericparams[i]).typedef).register_def; - end; - insert_generic_parameter_types(pd,nil,genericparams); - { the list is no longer required } - genericparams.free; - genericparams:=nil; - symtablestack.pop(pd.parast); - parse_generic:=true; - { also generate a dummy symbol if none exists already } - if assigned(astruct) then - dummysym:=tsym(astruct.symtable.find(spnongen)) + Message(parser_e_constructurs_cannot_take_type_parameters); + genericparams.free; + genericparams:=nil; + end else begin - dummysym:=tsym(symtablestack.top.find(spnongen)); - if not assigned(dummysym) and - (symtablestack.top=current_module.localsymtable) and - assigned(current_module.globalsymtable) then - dummysym:=tsym(current_module.globalsymtable.find(spnongen)); - end; - if not assigned(dummysym) then - begin - { overloading generic routines with non-generic types is not - allowed, so we create a procsym as dummy } - dummysym:=cprocsym.create(orgspnongen); + include(pd.defoptions,df_generic); + { push the parameter symtable so that constraint definitions are added + there and not in the owner symtable } + symtablestack.push(pd.parast); + { register the parameters } + for i:=0 to genericparams.count-1 do + begin + tsym(genericparams[i]).register_sym; + if tsym(genericparams[i]).typ=typesym then + tstoreddef(ttypesym(genericparams[i]).typedef).register_def; + end; + insert_generic_parameter_types(pd,nil,genericparams); + { the list is no longer required } + genericparams.free; + genericparams:=nil; + symtablestack.pop(pd.parast); + parse_generic:=true; + { also generate a dummy symbol if none exists already } if assigned(astruct) then - astruct.symtable.insert(dummysym) + dummysym:=tsym(astruct.symtable.find(spnongen)) else - symtablestack.top.insert(dummysym); - end - else if (dummysym.typ<>procsym) and - ( - { show error only for the declaration, not also the implementation } - not assigned(astruct) or - (symtablestack.top.symtablelevel<>main_program_level) - ) then - Message1(sym_e_duplicate_id,dummysym.realname); - if not (sp_generic_dummy in dummysym.symoptions) then - begin - include(dummysym.symoptions,sp_generic_dummy); - add_generic_dummysym(dummysym); + begin + dummysym:=tsym(symtablestack.top.find(spnongen)); + if not assigned(dummysym) and + (symtablestack.top=current_module.localsymtable) and + assigned(current_module.globalsymtable) then + dummysym:=tsym(current_module.globalsymtable.find(spnongen)); + end; + if not assigned(dummysym) then + begin + { overloading generic routines with non-generic types is not + allowed, so we create a procsym as dummy } + dummysym:=cprocsym.create(orgspnongen); + if assigned(astruct) then + astruct.symtable.insert(dummysym) + else + symtablestack.top.insert(dummysym); + end + else if (dummysym.typ<>procsym) and + ( + { show error only for the declaration, not also the implementation } + not assigned(astruct) or + (symtablestack.top.symtablelevel<>main_program_level) + ) then + Message1(sym_e_duplicate_id,dummysym.realname); + if not (sp_generic_dummy in dummysym.symoptions) then + begin + include(dummysym.symoptions,sp_generic_dummy); + add_generic_dummysym(dummysym); + end; + if dummysym.typ=procsym then + tprocsym(dummysym).add_generic_overload(aprocsym); + { start token recorder for the declaration } + pd.init_genericdecl; + current_scanner.startrecordtokens(pd.genericdecltokenbuf); end; - if dummysym.typ=procsym then - tprocsym(dummysym).add_generic_overload(aprocsym); - { start token recorder for the declaration } - pd.init_genericdecl; - current_scanner.startrecordtokens(pd.genericdecltokenbuf); end else if assigned(genericdef) then insert_generic_parameter_types(pd,tstoreddef(genericdef),generictypelist); diff --git a/avx512-0037785/compiler/pgenutil.pas b/avx512-0037785/compiler/pgenutil.pas index a4de4abf13..4804995dbb 100644 --- a/avx512-0037785/compiler/pgenutil.pas +++ b/avx512-0037785/compiler/pgenutil.pas @@ -990,7 +990,7 @@ uses paramdef2:=tconstsym(tstoreddef(def).genericparas[i]).constdef else paramdef2:=ttypesym(tstoreddef(def).genericparas[i]).typedef; - if not equal_defs(paramdef2,paramdef2) then + if not equal_defs(paramdef1,paramdef2) then begin allequal:=false; break; @@ -1379,8 +1379,6 @@ uses constraintdata : tgenericconstraintdata; old_block_type : tblock_type; fileinfo : tfileposinfo; - last_token : ttoken; - last_type_pos : tfileposinfo; begin result:=tfphashobjectlist.create(false); firstidx:=0; @@ -1389,8 +1387,6 @@ uses block_type:=bt_type; allowconst:=true; is_const:=false; - last_token:=NOTOKEN; - last_type_pos:=current_filepos; repeat if allowconst and try_to_consume(_CONST) then begin @@ -1605,8 +1601,6 @@ uses is_const:=false; allowconst:=true; end; - last_token:=token; - last_type_pos:=current_filepos; until not (try_to_consume(_COMMA) or try_to_consume(_SEMICOLON)); { if the constant parameter is not terminated then the type restriction was not specified and we need to give an error } diff --git a/avx512-0037785/compiler/psabiehpi.pas b/avx512-0037785/compiler/psabiehpi.pas index d38ebf15ba..c53a073314 100644 --- a/avx512-0037785/compiler/psabiehpi.pas +++ b/avx512-0037785/compiler/psabiehpi.pas @@ -688,19 +688,24 @@ implementation begincatchres, paraloc1: tcgpara; pd: tprocdef; - rttisym: TAsmSymbol; + {rttisym: TAsmSymbol; rttidef: tdef; + indirect: boolean; + otherunit: boolean; } wrappedexception: tregister; exceptloc: tlocation; - indirect: boolean; - otherunit: boolean; +{$if defined(i386) or defined(x86_64)} typeindex : aint; +{$endif} begin paraloc1.init; +{ rttidef:=nil; rttisym:=nil; +} wrappedexception:=hlcg.getaddressregister(list,voidpointertype); hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,wrappedexception); +(* if add_catch then begin if assigned(excepttype) then @@ -715,10 +720,13 @@ implementation rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect); end; end; +*) { check if the exception is handled by this node } if assigned(excepttype) then begin +{$if defined(i386) or defined(x86_64)} typeindex:=(current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(excepttype); +{$endif} current_asmdata.getjumplabel(catchstartlab); {$if defined(i386)} hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab); diff --git a/avx512-0037785/compiler/psub.pas b/avx512-0037785/compiler/psub.pas index 0d7ccbabe4..5d31dafcf1 100644 --- a/avx512-0037785/compiler/psub.pas +++ b/avx512-0037785/compiler/psub.pas @@ -1312,7 +1312,7 @@ implementation nodeset : THashSet absolute arg; entry : ptempinfo_flags_entry; i : longint; - hashsetitem: PHashSetItem; + {hashsetitem: PHashSetItem;} begin result:=fen_true; case n.nodetype of diff --git a/avx512-0037785/compiler/rgobj.pas b/avx512-0037785/compiler/rgobj.pas index 7f4f8ed5fb..b4ad622ae1 100644 --- a/avx512-0037785/compiler/rgobj.pas +++ b/avx512-0037785/compiler/rgobj.pas @@ -1692,7 +1692,9 @@ unit rgobj; colourednodes : Tsuperregisterset; adj_colours:set of 0..255; found : boolean; +{$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)} tmpr: tregister; +{$endif} begin spillednodes.clear; {Reset colours} @@ -1716,15 +1718,13 @@ unit rgobj; if supregset_in(colourednodes,a) and (reginfo[a].colour<=255) then include(adj_colours,reginfo[a].colour); end; + { e.g. AVR does not have a stack pointer register } +{$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)} { FIXME: temp variable r is needed here to avoid Internal error 20060521 } { while compiling the compiler. } tmpr:=NR_STACK_POINTER_REG; - { e.g. AVR does not have a stack pointer register } -{$if defined(RS_STACK_POINTER_REG)} - {$if (RS_STACK_POINTER_REG<>RS_INVALID)} if (regtype=getregtype(tmpr)) then include(adj_colours,RS_STACK_POINTER_REG); - {$ifend} {$ifend} {Assume a spill by default...} found:=false; @@ -2521,7 +2521,11 @@ unit rgobj; {Safe: this procedure is only called if there are spilled nodes.} with spillednodes do for i:=0 to length-1 do - tg.ungetiftemp(list,spill_temps^[buf^[i]]); + begin + j:=buf^[i]; + if tg.istemp(spill_temps^[j]) then + tg.ungettemp(list,spill_temps^[j]); + end; freemem(spill_temps); end; diff --git a/avx512-0037785/compiler/scandir.pas b/avx512-0037785/compiler/scandir.pas index f695e290c8..6df29a64e6 100644 --- a/avx512-0037785/compiler/scandir.pas +++ b/avx512-0037785/compiler/scandir.pas @@ -1362,7 +1362,6 @@ unit scandir; procedure dir_setpeflags; var - ident : string; flags : int64; begin if not (target_info.system in (systems_all_windows)) then @@ -1378,7 +1377,6 @@ unit scandir; procedure dir_setpeoptflags; var - ident : string; flags : int64; begin if not (target_info.system in (systems_all_windows)) then diff --git a/avx512-0037785/compiler/scanner.pas b/avx512-0037785/compiler/scanner.pas index 947d4d558a..649d2bc75a 100644 --- a/avx512-0037785/compiler/scanner.pas +++ b/avx512-0037785/compiler/scanner.pas @@ -135,6 +135,8 @@ interface { if nexttoken<>NOTOKEN, then nexttokenpos holds its filepos } next_filepos : tfileposinfo; + { current macro nesting depth } + macro_nesting_depth, comment_level, yylexcount : longint; ignoredirectives : TFPHashList; { ignore directives, used to give warnings only once } @@ -2922,7 +2924,10 @@ type if assigned(inputfile.next) then begin if inputfile.is_macro then - to_dispose:=inputfile + begin + to_dispose:=inputfile; + dec(macro_nesting_depth); + end else begin to_dispose:=nil; @@ -3686,6 +3691,7 @@ type addfile(hp); with inputfile do begin + inc(macro_nesting_depth); setmacro(p,len); { local buffer } inputbuffer:=buf; @@ -4868,7 +4874,7 @@ type mac:=tmacro(search_macro(pattern)); if assigned(mac) and (not mac.is_compiler_var) and (assigned(mac.buftext)) then begin - if yylexcount<max_macro_nesting then + if (yylexcount<max_macro_nesting) and (macro_nesting_depth<max_macro_nesting) then begin mac.is_used:=true; inc(yylexcount); diff --git a/avx512-0037785/compiler/symdef.pas b/avx512-0037785/compiler/symdef.pas index 04c0bb64b6..da190640ad 100644 --- a/avx512-0037785/compiler/symdef.pas +++ b/avx512-0037785/compiler/symdef.pas @@ -2343,8 +2343,10 @@ implementation function tstoreddef.is_intregable : boolean; +{$ifndef cpuhighleveltarget} var recsize,temp: longint; +{$endif cpuhighleveltarget} begin case typ of orddef, diff --git a/avx512-0037785/compiler/systems.pas b/avx512-0037785/compiler/systems.pas index 1828b1dfde..a93a2f6c64 100644 --- a/avx512-0037785/compiler/systems.pas +++ b/avx512-0037785/compiler/systems.pas @@ -451,6 +451,8 @@ interface + [system_i386_beos,system_i386_haiku] + [system_powerpc_morphos]; + systems_support_uf2 = [system_arm_embedded,system_avr_embedded,system_mipsel_embedded,system_xtensa_embedded]; + { all internal COFF writers } asms_int_coff = [as_arm_pecoffwince,as_x86_64_pecoff,as_i386_pecoffwince, as_i386_pecoffwdosx,as_i386_pecoff,as_i386_coff]; diff --git a/avx512-0037785/compiler/systems/t_amiga.pas b/avx512-0037785/compiler/systems/t_amiga.pas index 8efdd79a57..03a2896952 100644 --- a/avx512-0037785/compiler/systems/t_amiga.pas +++ b/avx512-0037785/compiler/systems/t_amiga.pas @@ -262,6 +262,7 @@ begin Add(' .data : {'); Add(' PROVIDE(_DATA_BASE_ = .);'); Add(' *(.data .data.* .gnu.linkonce.d.*)'); + Add(' *(fpc.resources)'); Add(' VBCC_CONSTRUCTORS_ELF'); Add(' }'); Add(' .ctors : { *(.ctors .ctors.*) }'); @@ -293,6 +294,7 @@ begin Add(' .plt : { *(.plt) }'); Add(' .bss : {'); Add(' *(.bss .bss.* .gnu.linkonce.b.*)'); + Add(' *(fpc.reshandles)'); Add(' *(COMMON)'); Add(' }'); Add(' .bss68k : { *(BSS bss) }'); diff --git a/avx512-0037785/compiler/systems/t_bsd.pas b/avx512-0037785/compiler/systems/t_bsd.pas index 14ad1b0298..3fafadece6 100644 --- a/avx512-0037785/compiler/systems/t_bsd.pas +++ b/avx512-0037785/compiler/systems/t_bsd.pas @@ -231,7 +231,6 @@ end; Function TLinkerBSD.WriteResponseFile(isdll:boolean) : Boolean; Var linkres : TLinkRes; - FilesList : TLinkRes; i : longint; HPath : TCmdStrListItem; s,s1,s2 : TCmdStr; @@ -581,7 +580,6 @@ var targetstr, emulstr : TCmdStr; GCSectionsStr : string[63]; - exportedsyms: text; success : boolean; begin MakeSharedLibrary:=false; diff --git a/avx512-0037785/compiler/systems/t_darwin.pas b/avx512-0037785/compiler/systems/t_darwin.pas index 3de7f8a752..2663930879 100644 --- a/avx512-0037785/compiler/systems/t_darwin.pas +++ b/avx512-0037785/compiler/systems/t_darwin.pas @@ -320,8 +320,7 @@ implementation FilesList : TLinkRes; i : longint; HPath : TCmdStrListItem; - s,s1,s2 : TCmdStr; - Fl1,Fl2 : Boolean; + s : TCmdStr; begin WriteResponseFile:=False; if ReOrderEntries Then @@ -482,7 +481,7 @@ implementation emulstr:=''; ltostr:=''; if (cs_link_map in current_settings.globalswitches) then - mapstr:='-Map '+maybequoted(ChangeFileExt(current_module.exefilename,'.map')); + mapstr:='-map '+maybequoted(ChangeFileExt(current_module.exefilename,'.map')); if (cs_link_staticflag in current_settings.globalswitches) then StaticStr:='-static'; diff --git a/avx512-0037785/compiler/systems/t_embed.pas b/avx512-0037785/compiler/systems/t_embed.pas index a6e4b684f2..dc53666be8 100644 --- a/avx512-0037785/compiler/systems/t_embed.pas +++ b/avx512-0037785/compiler/systems/t_embed.pas @@ -39,6 +39,7 @@ implementation TlinkerEmbedded=class(texternallinker) private Function WriteResponseFile: Boolean; + Function GenerateUF2(binFile,uf2File : string;baseAddress : longWord):boolean; public constructor Create; override; procedure SetDefaultInfo; override; @@ -1653,6 +1654,10 @@ begin success:=DoExec(FindUtil(utilsprefix+'objcopy'),'-O binary '+ FixedExeFileName+' '+ maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.bin'))),true,false); + if success and (target_info.system in systems_support_uf2) and (cs_generate_uf2 in current_settings.globalswitches) then + success := GenerateUF2(maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.bin'))), + maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.uf2'))), + embedded_controllers[current_settings.controllertype].flashbase); {$ifdef ARM} if success and (current_settings.controllertype = ct_raspi2) then success:=DoExec(FindUtil(utilsprefix+'objcopy'),'-O binary '+ FixedExeFileName + ' kernel7.img',true,false); @@ -1669,6 +1674,106 @@ function TLinkerEmbedded.postprocessexecutable(const fn : string;isdll:boolean): end; +function TlinkerEmbedded.GenerateUF2(binFile,uf2File : string;baseAddress : longWord):boolean; +type + TFamilies= record + k : String; + v : longWord; + end; + tuf2Block = record + magicStart0, + magicStart1, + flags, + targetAddr, + payloadSize, + blockNo, + numBlocks, + familyid : longWord; + data : array[0..255] of byte; + padding : array[0..511-256-32-4] of byte; + magicEnd : longWord; + end; + +const + Families : array of TFamilies = ( + (k:'SAMD21'; v:$68ed2b88), + (k:'SAML21'; v:$1851780a), + (k:'SAMD51'; v:$55114460), + (k:'NRF52'; v:$1b57745f), + (k:'STM32F0';v:$647824b6), + (k:'STM32F1';v:$5ee21072), + (k:'STM32F2';v:$5d1a0a2e), + (k:'STM32F3';v:$6b846188), + (k:'STM32F4';v:$57755a57), + (k:'STM32F7';v:$53b80f00), + (k:'STM32G0';v:$300f5633), + (k:'STM32G4';v:$4c71240a), + (k:'STM32H7';v:$6db66082), + (k:'STM32L0';v:$202e3a91), + (k:'STM32L1';v:$1e1f432d), + (k:'STM32L4';v:$00ff6919), + (k:'STM32L5';v:$04240bdf), + (k:'STM32WB';v:$70d16653), + (k:'STM32WL';v:$21460ff0) + ); + +var + f,g : file; + uf2block : Tuf2Block; + totalRead,numRead : longWord; + familyId,i : longWord; + ExtraOptions : String; + +begin + if pos('-Ttext=',Info.ExtraOptions) > 0 then + begin + ExtraOptions := copy(Info.ExtraOptions,pos('-Ttext=',Info.ExtraOptions)+7,length(Info.ExtraOptions)); + for i := 1 to length(ExtraOptions) do + if pos(copy(ExtraOptions,i,1),'0123456789abcdefxABCDEFX') = 0 then + ExtraOptions := copy(ExtraOptions,1,i); + baseAddress := StrToIntDef(ExtraOptions,0); + end; + + familyId := 0; + for i := 0 to length(Families)-1 do + begin + if pos(Families[i].k,embedded_controllers[current_settings.controllertype].controllerunitstr) = 1 then + familyId := Families[i].v; + end; + + if (baseAddress and $07ffffff) <> 0 then + begin + totalRead := 0; + numRead := 0; + assign(f,binfile); + reset(f,1); + assign(g,uf2file); + rewrite(g,1); + + repeat + fillchar(uf2block,sizeof(uf2block),0); + uf2block.magicStart0 := $0A324655; // "UF2\n" + uf2block.magicStart1 := $9E5D5157; // Randomly selected + if familyId = 0 then + uf2block.flags := 0 + else + uf2block.flags := $2000; + uf2block.targetAddr := baseAddress + totalread; + uf2block.payloadSize := 256; + uf2block.blockNo := (totalRead div sizeOf(uf2block.data)); + uf2block.numBlocks := (filesize(f) + 255) div 256; + uf2block.familyId := familyId; + uf2block.magicEnd := $0AB16F30; // Randomly selected + blockRead(f,uf2block.data,sizeof(uf2block.data),numRead); + blockwrite(g,uf2block,sizeof(uf2block)); + inc(totalRead,numRead); + until (numRead=0) or (NumRead<>sizeOf(uf2block.data)); + close(f); + close(g); + end; + Result := true; +end; + {***************************************************************************** TlinkerEmbedded_SdccSdld *****************************************************************************} @@ -1676,17 +1781,14 @@ function TLinkerEmbedded.postprocessexecutable(const fn : string;isdll:boolean): function TlinkerEmbedded_SdccSdld.WriteResponseFile: Boolean; Var linkres : TLinkRes; - i : longint; - HPath : TCmdStrListItem; - s,s1,s2 : TCmdStr; + //i : longint; + //HPath : TCmdStrListItem; + s{,s1,s2} : TCmdStr; prtobj, cprtobj : string[80]; linklibc : boolean; - found1, - found2 : boolean; - {$if defined(ARM)} - LinkStr : string; - {$endif} + //found1, + //found2 : boolean; begin WriteResponseFile:=False; linklibc:=(SharedLibFiles.Find('c')<>nil); diff --git a/avx512-0037785/compiler/systems/t_freertos.pas b/avx512-0037785/compiler/systems/t_freertos.pas index d3e36d923a..027d29f15c 100644 --- a/avx512-0037785/compiler/systems/t_freertos.pas +++ b/avx512-0037785/compiler/systems/t_freertos.pas @@ -81,8 +81,7 @@ Var i : longint; HPath : TCmdStrListItem; s,s1,s2 : TCmdStr; - prtobj, - cprtobj : string[80]; + prtobj : string[80]; linklibc : boolean; found1, found2 : boolean; @@ -96,9 +95,8 @@ begin prtobj:=''; {$else} prtobj:='prt0'; - cprtobj:='cprt0'; if linklibc then - prtobj:=cprtobj; + prtobj:='cprt0'; {$endif} { Open link.res file } @@ -944,7 +942,6 @@ end; function TlinkerFreeRTOS.MakeExecutable:boolean; var StaticStr, - S, binstr, cmdstr, mapstr: Ansistring; @@ -953,9 +950,12 @@ var DynLinkStr, StripStr, FixedExeFileName: string; +{$ifdef XTENSA} + S: Ansistring; t: Text; hp: TCmdStrListItem; filepath: TCmdStr; +{$endif XTENSA} begin {$ifdef XTENSA} { idfpath can be set by -Ff, else default to environment value of IDF_PATH } diff --git a/avx512-0037785/compiler/systems/t_win.pas b/avx512-0037785/compiler/systems/t_win.pas index 887787f8e9..05e50d1c94 100644 --- a/avx512-0037785/compiler/systems/t_win.pas +++ b/avx512-0037785/compiler/systems/t_win.pas @@ -430,7 +430,9 @@ implementation l1,l2,l3,l4 {$ifdef ARM} ,l5 {$endif ARM} : tasmlabel; importname : string; suffix : integer; +{$ifndef AARCH64} href : treference; +{$endif AARCH64} i,j : longint; ImportLibrary : TImportLibrary; ImportSymbol : TImportSymbol; diff --git a/avx512-0037785/compiler/systems/t_win16.pas b/avx512-0037785/compiler/systems/t_win16.pas index 8b76d09151..587c121a69 100644 --- a/avx512-0037785/compiler/systems/t_win16.pas +++ b/avx512-0037785/compiler/systems/t_win16.pas @@ -104,7 +104,6 @@ var i,j: Integer; ImportLibrary: TImportLibrary; ImportSymbol: TImportSymbol; - AsmPrefix: String; procedure AddImport(const dllname,afuncname,mangledname:string;ordnr:longint;isvar:boolean); begin @@ -114,7 +113,6 @@ var end; begin - AsmPrefix:='imp'+Lower(current_module.modulename^); current_module.linkotherstaticlibs.add(current_module.importlibfilename,link_always); ObjWriter:=TOmfLibObjectWriter.CreateAr(current_module.importlibfilename,32); ObjOutput:=TOmfObjOutput.Create(ObjWriter); @@ -238,7 +236,6 @@ function TExternalLinkerWin16WLink.WriteResponseFile(isdll: boolean): Boolean; Var linkres : TLinkRes; s : string; - i: Integer; begin WriteResponseFile:=False; diff --git a/avx512-0037785/compiler/utils/Makefile b/avx512-0037785/compiler/utils/Makefile index aa2def26a7..3b69835f57 100644 --- a/avx512-0037785/compiler/utils/Makefile +++ b/avx512-0037785/compiler/utils/Makefile @@ -351,316 +351,316 @@ ifdef OPTNEW override FPCOPT+=$(OPTNEW) endif ifeq ($(FULL_TARGET),i386-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-go32v2) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-win32) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-os2) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-freebsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-beos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-haiku) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-solaris) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-netware) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-openbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-wdosx) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-darwin) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-emx) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-watcom) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-netwlibc) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-wince) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-symbian) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-nativent) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-iphonesim) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-aros) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-amiga) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-atari) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-palmos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-macosclassic) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),m68k-sinclairql) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-amiga) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-macosclassic) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-darwin) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-morphos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-wii) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc-aix) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),sparc-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),sparc-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),sparc-solaris) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),sparc-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-freebsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-haiku) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-solaris) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-openbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-darwin) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-win64) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-iphonesim) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-aros) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),x86_64-dragonfly) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-netbsd) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-palmos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-wince) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-gba) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-nds) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-symbian) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-aros) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-freertos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),arm-ios) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc64-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc64-darwin) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc64-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),powerpc64-aix) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),avr-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),armeb-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),armeb-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),mips-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),mipsel-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),mipsel-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),mipsel-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),mips64el-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),jvm-java) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),jvm-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i8086-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i8086-msdos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i8086-win16) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),aarch64-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),aarch64-darwin) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),aarch64-win64) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),aarch64-android) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),aarch64-ios) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),wasm-wasm) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),sparc64-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),riscv32-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),riscv32-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),riscv64-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),riscv64-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),xtensa-linux) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),xtensa-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),xtensa-freertos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),z80-embedded) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),z80-zxspectrum) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),z80-msxdos) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),z80-amstradcpc) -override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins endif ifeq ($(FULL_TARGET),i386-linux) override CLEAN_UNITS+=ppu crc diff --git a/avx512-0037785/compiler/utils/Makefile.fpc b/avx512-0037785/compiler/utils/Makefile.fpc index be979a987e..1ae4baa30c 100644 --- a/avx512-0037785/compiler/utils/Makefile.fpc +++ b/avx512-0037785/compiler/utils/Makefile.fpc @@ -3,7 +3,7 @@ # [target] -programs=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins +programs=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins rst=fpcsubst [clean] diff --git a/avx512-0037785/compiler/utils/mkx86inl.pp b/avx512-0037785/compiler/utils/mkx86inl.pp index 92e218306c..fe784a2c7e 100644 --- a/avx512-0037785/compiler/utils/mkx86inl.pp +++ b/avx512-0037785/compiler/utils/mkx86inl.pp @@ -4,8 +4,7 @@ program mkx86inl; {$H+} uses - sysutils, classes, - strutils; + sysutils, classes; type TOperDirection = (operIn, operVar, operOut); @@ -19,6 +18,93 @@ type const DirLUT: array[TOperDirection] of string = ('','var ','out '); +{ *************************************************************************** + the routines Copy2SymbDel, PosSetEx, PosSet, RemoveTrailingChars, TrimRightSet are copied and reformatted + from StrUtils and thus covered by the copyright of strutils (see below) as compiler utilities cannot + depend on packages + + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by the Free Pascal development team + + 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. +*************************************************************************** } + +function Copy2SymbDel(var S: string; Symb: Char): string; + var + p: SizeInt; + begin + p:=Pos(Symb,S); + if p=0 then + begin + result:=s; + s:=''; + end + else + begin + Result:=Copy(S,1,p-1); + delete(s,1,p); + end; + end; + + +function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt; + var + i,j:SizeInt; + begin + if pchar(pointer(s))=nil then + j:=0 + else + begin + i:=length(s); + j:=count; + if j>i then + begin + result:=0; + exit; + end; + while (j<=i) and (not (s[j] in c)) do inc(j); + if (j>i) then + j:=0; // not found. + end; + result:=j; + end; + +function PosSet(const c: TSysCharSet; const s: ansistring): SizeInt; + begin + result:=possetex(c,s,1); + end; + +procedure RemoveTrailingChars(VAR S: AnsiString; const CSet: TSysCharset); + var + I,J: LONGINT; + + Begin + I:=Length(S); + IF (I>0) Then + Begin + J:=I; + While (j>0) and (S[J] IN CSet) DO DEC(J); + IF J<>I Then + SetLength(S,J); + End; + End; + +function TrimRightSet(const S: String; const CSet: TSysCharSet): String; + +begin + result:=s; + RemoveTrailingchars(result,cset); +end; + +{ *************************************************************************** + end of StrUtils code + ***************************************************************************} + function GetPascalType(const ATyp: string): string; begin case ATyp of diff --git a/avx512-0037785/compiler/utils/mkz80ins.pp b/avx512-0037785/compiler/utils/mkz80ins.pp index 3c12563fa1..f94e752731 100644 --- a/avx512-0037785/compiler/utils/mkz80ins.pp +++ b/avx512-0037785/compiler/utils/mkz80ins.pp @@ -18,7 +18,7 @@ program mkz80ins; {$mode objfpc}{$H+} uses - SysUtils,StrUtils; + SysUtils; const Version = '1.0.0'; @@ -84,6 +84,37 @@ type destructor Destroy;override; end; +{ *************************************************************************** + the routines LeftStr, AnsiStartsStr are copied and reformatted + from StrUtils and thus covered by the copyright of strutils (see below) as compiler utilities cannot + depend on packages + + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by the Free Pascal development team + + 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. +*************************************************************************** } + +function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString; + begin + Result:=Copy(AText,1,ACount); + end; + + +function AnsiStartsStr(const ASubText, AText: string): Boolean; + begin + Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText); + end; + +{ *************************************************************************** + end of StrUtils code +***************************************************************************} + function PasEncode(const S: string): string; var Ch: Char; diff --git a/avx512-0037785/compiler/utils/msg2inc.pp b/avx512-0037785/compiler/utils/msg2inc.pp index 9e8e45787f..38a7c7f700 100644 --- a/avx512-0037785/compiler/utils/msg2inc.pp +++ b/avx512-0037785/compiler/utils/msg2inc.pp @@ -13,6 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} +{$H+} program msg2inc; {$ifdef unix} @@ -622,21 +623,28 @@ Var hs : string; begin hs:=''; - for i:=1 to length(s) do - case S[i] of - '$' : - if (s[i+1] in ['0'..'9']) then - hs:=hs+'arg' - else - hs:=hs+'\$'; - '&','{','}','#','_','%': // Escape these characters - hs := hs + '\' + S[i]; - '~','^': - hs := hs + '\'+S[i]+' '; - '\': - hs:=hs+'$\backslash$' - else - hs := hs + S[i]; + i:=1; + while i<=length(s) do + begin + case S[i] of + '$' : + if (s[i+1] in ['0'..'9']) then + begin + hs:=hs+'\textlangle arg. '+s[i+1]+'\textrangle{}'; + inc(i); + end + else + hs:=hs+'\$'; + '&','{','}','#','_','%': // Escape these characters + hs := hs + '\' + S[i]; + '~','^': + hs := hs + '\'+S[i]+' '; + '\': + hs:=hs+'$\backslash$' + else + hs := hs + S[i]; + end; + inc(i); end; EscapeString:=hs; end; @@ -646,6 +654,7 @@ var t,f : text; line, i,k : longint; + number, s,s1 : string; texoutput : boolean; begin @@ -695,25 +704,35 @@ begin if i>0 then begin inc(i); + number:=''; while s[i] in ['0'..'9'] do - inc(i); + begin + number:=number+s[i]; + inc(i); + end; + { strip leading zeros } + while number[1]='0' do + Delete(number,1,1); inc(i); s1:=''; k:=0; while (k<5) and (s[i+k]<>'_') do begin case s[i+k] of - 'W' : s1:='Warning: '; - 'E' : s1:='Error: '; - 'F' : s1:='Fatal: '; - 'N' : s1:='Note: '; - 'I' : s1:='Info: '; - 'H' : s1:='Hint: '; + 'W' : s1:='Warning '+number+': '; + 'E' : s1:='Error '+number+': '; + 'F' : s1:='Fatal error '+number+': '; + 'N' : s1:='Note '+number+': '; + 'I' : s1:='Info '+number+': '; + 'H' : s1:='Hint '+number+': '; end; inc(k); end; if s[i+k]='_' then inc(i,k+1); + if number<>'' then + writeln(t,'\index[msgnr]{',number,'}'); + writeln(t,'\index[msgtxt]{',escapestring(Copy(s,i,255)),'}'); writeln(t,'\item ['+s1+escapestring(Copy(s,i,255))+'] \hfill \\'); end else diff --git a/avx512-0037785/compiler/utils/ppuutils/ppudump.pp b/avx512-0037785/compiler/utils/ppuutils/ppudump.pp index bc06c393d5..50f708105c 100644 --- a/avx512-0037785/compiler/utils/ppuutils/ppudump.pp +++ b/avx512-0037785/compiler/utils/ppuutils/ppudump.pp @@ -2305,7 +2305,8 @@ const 'Link using vlink', {cs_link_vlink} 'Link-Time Optimization disabled for system unit', {cs_lto_nosystem} 'Assemble on target OS', {cs_asemble_on_target} - 'Use a memory model to support >2GB static data on 64 Bit target' {cs_large} + 'Use a memory model to support >2GB static data on 64 Bit target', {cs_large} + 'Generate UF2 binary' {cs_generate_uf2} ); localswitchname : array[tlocalswitch] of string[50] = { Switches which can be changed locally } diff --git a/avx512-0037785/compiler/verbose.pas b/avx512-0037785/compiler/verbose.pas index a6003eeaf2..bc48697a02 100644 --- a/avx512-0037785/compiler/verbose.pas +++ b/avx512-0037785/compiler/verbose.pas @@ -753,7 +753,7 @@ implementation UpdateStatus; { Fix replacements } DefaultReplacements(s); - if status.showmsgnrs then + if status.showmsgnrs and ((v and V_Normal)=0) then s:='('+tostr(w)+') '+s; if doqueue then begin diff --git a/avx512-0037785/compiler/x86/aasmcpu.pas b/avx512-0037785/compiler/x86/aasmcpu.pas index 699e009466..eeb6044d77 100644 --- a/avx512-0037785/compiler/x86/aasmcpu.pas +++ b/avx512-0037785/compiler/x86/aasmcpu.pas @@ -924,6 +924,7 @@ implementation Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 2B: Instruction Set Reference, N-Z, January 2015 } +{$ifndef i8086} alignarray_cmovcpus:array[0..10] of string[11]=( #$66#$66#$66#$0F#$1F#$84#$00#$00#$00#$00#$00, #$66#$66#$0F#$1F#$84#$00#$00#$00#$00#$00, @@ -936,6 +937,7 @@ implementation #$0F#$1F#$00, #$66#$90, #$90); +{$endif i8086} {$ifdef i8086} alignarray:array[0..5] of string[8]=( #$90#$90#$90#$90#$90#$90#$90, @@ -3690,13 +3692,17 @@ implementation needed_VEX_Extension: boolean; needed_VEX: boolean; needed_EVEX: boolean; +{$ifdef x86_64} needed_VSIB: boolean; +{$endif x86_64} opmode: integer; VEXvvvv: byte; VEXmmmmm: byte; +{ VEXw : byte; VEXpp : byte; VEXll : byte; +} EVEXvvvv: byte; EVEXpp: byte; EVEXr: byte; @@ -3795,14 +3801,17 @@ implementation needed_VEX := false; needed_EVEX := false; needed_VEX_Extension := false; +{$ifdef x86_64} needed_VSIB := false; +{$endif x86_64} opmode := -1; VEXvvvv := 0; VEXmmmmm := 0; - +{ VEXll := 0; VEXw := 0; VEXpp := 0; +} EVEXpp := 0; EVEXvvvv := 0; EVEXr := 0; @@ -3855,7 +3864,9 @@ implementation begin // VSIB memory addresing if getsupreg(oper[opidx]^.ref^.index) and $10 = $0 then EVEXv := 1; // VECTOR-Index + {$ifdef x86_64} needed_VSIB := true; + {$endif x86_64} end; end; else @@ -3866,12 +3877,12 @@ implementation end; &333: begin VEXvvvv := VEXvvvv OR $02; // set SIMD-prefix $F3 - VEXpp := $02; // set SIMD-prefix $F3 + //VEXpp := $02; // set SIMD-prefix $F3 EVEXpp := $02; // set SIMD-prefix $F3 end; &334: begin VEXvvvv := VEXvvvv OR $03; // set SIMD-prefix $F2 - VEXpp := $03; // set SIMD-prefix $F2 + //VEXpp := $03; // set SIMD-prefix $F2 EVEXpp := $03; // set SIMD-prefix $F2 end; &350: needed_EVEX := true; // AVX512 instruction or AVX128/256/512-instruction (depended on operands [x,y,z]mm16..) @@ -3879,18 +3890,18 @@ implementation &352: EVEXw1 := $01; &361: begin VEXvvvv := VEXvvvv OR $01; // set SIMD-prefix $66 - VEXpp := $01; // set SIMD-prefix $66 + //VEXpp := $01; // set SIMD-prefix $66 EVEXpp := $01; // set SIMD-prefix $66 end; &362: needed_VEX := true; &363: begin needed_VEX_Extension := true; VEXvvvv := VEXvvvv OR (1 shl 7); // set REX.W - VEXw := 1; + //VEXw := 1; end; &364: begin VEXvvvv := VEXvvvv OR $04; // vectorlength = 256 bits AND no scalar - VEXll := $01; + //VEXll := $01; EVEXll := $01; end; &366, diff --git a/avx512-0037785/compiler/x86/agx86nsm.pas b/avx512-0037785/compiler/x86/agx86nsm.pas index cbff191756..a4f28adafe 100644 --- a/avx512-0037785/compiler/x86/agx86nsm.pas +++ b/avx512-0037785/compiler/x86/agx86nsm.pas @@ -53,7 +53,9 @@ interface private FSections: TFPHashObjectList; FGroups: TFPHashObjectList; +{$ifndef i8086} using_relative : boolean; +{$endif i8086} function CodeSectionName(const aname:string): string; procedure WriteReference(var ref : treference); procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean); @@ -681,10 +683,6 @@ interface end; procedure TX86NasmAssembler.WriteGroups; - {$ifdef i8086} - var - i: Integer; - {$endif i8086} begin {$ifdef i8086} if target_info.system in [system_i8086_msdos,system_i8086_win16,system_i8086_embedded] then diff --git a/avx512-0037785/compiler/x86/aoptx86.pas b/avx512-0037785/compiler/x86/aoptx86.pas index 4b38629c44..83fc2deb84 100644 --- a/avx512-0037785/compiler/x86/aoptx86.pas +++ b/avx512-0037785/compiler/x86/aoptx86.pas @@ -122,6 +122,7 @@ unit aoptx86; function PrePeepholeOptSxx(var p : tai) : boolean; function PrePeepholeOptIMUL(var p : tai) : boolean; + function OptPass1Add(var p: tai): boolean; function OptPass1AND(var p : tai) : boolean; function OptPass1_V_MOVAP(var p : tai) : boolean; function OptPass1VOP(var p : tai) : boolean; @@ -1653,9 +1654,6 @@ unit aoptx86; { Replaces all references to AOldReg in a memory reference to ANewReg } class function TX86AsmOptimizer.ReplaceRegisterInRef(var ref: TReference; const AOldReg, ANewReg: TRegister): Boolean; - var - OldSupReg: TSuperRegister; - OldSubReg, MemSubReg: TSubRegister; begin Result := False; { For safety reasons, only check for exact register matches } @@ -1680,7 +1678,7 @@ unit aoptx86; class function TX86AsmOptimizer.ReplaceRegisterInOper(const p: taicpu; const OperIdx: Integer; const AOldReg, ANewReg: TRegister): Boolean; var OldSupReg, NewSupReg: TSuperRegister; - OldSubReg, NewSubReg, MemSubReg: TSubRegister; + OldSubReg, NewSubReg: TSubRegister; OldRegType: TRegisterType; ThisOper: POper; begin @@ -1838,7 +1836,6 @@ unit aoptx86; function TX86AsmOptimizer.DeepMOVOpt(const p_mov: taicpu; const hp: taicpu): Boolean; var CurrentReg, ReplaceReg: TRegister; - SubReg: TSubRegister; begin Result := False; @@ -3171,10 +3168,45 @@ unit aoptx86; end; + function TX86AsmOptimizer.OptPass1Add(var p : tai) : boolean; + var + hp1 : tai; + begin + result:=false; + { replace + addX const,%reg1 + leaX (%reg1,%reg1,Y),%reg2 // Base or index might not be equal to reg1 + dealloc %reg1 + + by + + leaX const+const*Y(%reg1,%reg1,Y),%reg2 + } + if MatchOpType(taicpu(p),top_const,top_reg) and + GetNextInstruction(p,hp1) and + MatchInstruction(hp1,A_LEA,[taicpu(p).opsize]) and + ((taicpu(p).oper[1]^.reg=taicpu(hp1).oper[0]^.ref^.base) or + (taicpu(p).oper[1]^.reg=taicpu(hp1).oper[0]^.ref^.index)) then + begin + TransferUsedRegs(TmpUsedRegs); + UpdateUsedRegs(TmpUsedRegs, tai(p.next)); + if not(RegUsedAfterInstruction(taicpu(p).oper[1]^.reg,hp1,TmpUsedRegs)) then + begin + DebugMsg(SPeepholeOptimization + 'AddLea2Lea done',p); + if taicpu(p).oper[1]^.reg=taicpu(hp1).oper[0]^.ref^.base then + inc(taicpu(hp1).oper[0]^.ref^.offset,taicpu(p).oper[0]^.val); + if taicpu(p).oper[1]^.reg=taicpu(hp1).oper[0]^.ref^.index then + inc(taicpu(hp1).oper[0]^.ref^.offset,taicpu(p).oper[0]^.val*max(taicpu(hp1).oper[0]^.ref^.scalefactor,1)); + RemoveCurrentP(p); + result:=true; + end; + end; + end; + + function TX86AsmOptimizer.OptPass1LEA(var p : tai) : boolean; var - hp1, hp2, hp3: tai; - l : ASizeInt; + hp1: tai; ref: Integer; saveref: treference; TempReg: TRegister; @@ -3350,7 +3382,11 @@ unit aoptx86; ) or ((taicpu(hp1).oper[0]^.ref^.base=taicpu(p).oper[1]^.reg) and (taicpu(hp1).oper[0]^.ref^.scalefactor <= 1) and - (taicpu(p).oper[0]^.ref^.base=NR_NO) and + ((taicpu(p).oper[0]^.ref^.base=NR_NO) or + ((taicpu(p).oper[0]^.ref^.base=taicpu(p).oper[0]^.ref^.base) and + (taicpu(p).oper[0]^.ref^.index=NR_NO) + ) + ) and not(RegUsedBetween(taicpu(p).oper[0]^.ref^.index,p,hp1))) ) and not(RegUsedBetween(taicpu(p).oper[0]^.ref^.base,p,hp1)) and @@ -4945,7 +4981,7 @@ unit aoptx86; MinSize, MaxSize, TrySmaller, TargetSize: TOpSize; TargetSubReg: TSubRegister; hp1, hp2: tai; - RegInUse, p_removed: Boolean; + RegInUse, RegChanged, p_removed: Boolean; { Store list of found instructions so we don't have to call GetNextInstructionUsingReg multiple times } @@ -4995,6 +5031,7 @@ unit aoptx86; TrySmallerLimit := UpperLimit; TrySmaller := S_NO; SmallerOverflow := False; + RegChanged := False; while GetNextInstructionUsingReg(hp1, hp1, ThisReg) and (hp1.typ = ait_instruction) and @@ -5377,6 +5414,7 @@ unit aoptx86; begin DebugMsg(SPeepholeOptimization + 'Simplified register usage so ' + debug_regname(taicpu(hp1).oper[1]^.reg) + ' = ' + debug_regname(taicpu(p).oper[1]^.reg), p); ThisReg := taicpu(hp1).oper[1]^.reg; + RegChanged := True; TransferUsedRegs(TmpUsedRegs); AllocRegBetween(ThisReg, p, hp1, TmpUsedRegs); @@ -5411,9 +5449,12 @@ unit aoptx86; { Now go through every instruction we found and change the size. If TargetSize = MaxSize, then almost no changes are needed and Result can remain False if it hasn't been set - yet. } + yet. + + If RegChanged is True, then the register requires changing + and so the point about TargetSize = MaxSize doesn't apply. } - if (TargetSize <> MaxSize) and (InstrMax >= 0) then + if ((TargetSize <> MaxSize) or RegChanged) and (InstrMax >= 0) then begin for Index := 0 to InstrMax do begin @@ -5640,99 +5681,100 @@ unit aoptx86; function TX86AsmOptimizer.OptPass2Jcc(var p : tai) : boolean; var - hp1,hp2,hp3,hp4,hpmov2: tai; - carryadd_opcode : TAsmOp; + hp1,hp2: tai; +{$ifndef i8086} + hp3,hp4,hpmov2: tai; l : Longint; condition : TAsmCond; +{$endif i8086} + carryadd_opcode : TAsmOp; symbol: TAsmSymbol; reg: tsuperregister; - regavailable: Boolean; + increg, tmpreg: TRegister; begin result:=false; - symbol:=nil; - if GetNextInstruction(p,hp1) then + if GetNextInstruction(p,hp1) and (hp1.typ=ait_instruction) then begin symbol := TAsmLabel(taicpu(p).oper[0]^.ref^.symbol); - if (hp1.typ=ait_instruction) and - GetNextInstruction(hp1,hp2) and - ((hp2.typ=ait_label) or - { trick to skip align } + if GetNextInstruction(hp1,hp2) and + ( + (hp2.typ=ait_label) or + { trick to skip align } ((hp2.typ=ait_align) and GetNextInstruction(hp2,hp2) and (hp2.typ=ait_label)) - ) and - (Tasmlabel(symbol) = Tai_label(hp2).labsym) then - { jb @@1 cmc - inc/dec operand --> adc/sbb operand,0 - @@1: + ) and + (Tasmlabel(symbol) = Tai_label(hp2).labsym) and + ( + ( + ((Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB)) and + MatchOptype(Taicpu(hp1),top_const,top_reg) and + (Taicpu(hp1).oper[0]^.val=1) + ) or + ((Taicpu(hp1).opcode=A_INC) or (Taicpu(hp1).opcode=A_DEC)) + ) then + { jb @@1 cmc + inc/dec operand --> adc/sbb operand,0 + @@1: - ... and ... + ... and ... - jnb @@1 - inc/dec operand --> adc/sbb operand,0 - @@1: } + jnb @@1 + inc/dec operand --> adc/sbb operand,0 + @@1: } begin - carryadd_opcode:=A_NONE; if Taicpu(p).condition in [C_NAE,C_B,C_C] then begin - if (Taicpu(hp1).opcode=A_INC) or - ((Taicpu(hp1).opcode=A_ADD) and - MatchOptype(Taicpu(hp1),top_const,top_reg) and - (Taicpu(hp1).oper[0]^.val=1) - ) then - carryadd_opcode:=A_ADC; - if (Taicpu(hp1).opcode=A_DEC) or - ((Taicpu(hp1).opcode=A_SUB) and - MatchOptype(Taicpu(hp1),top_const,top_reg) and - (Taicpu(hp1).oper[0]^.val=1) - ) then - carryadd_opcode:=A_SBB; - if carryadd_opcode<>A_NONE then - begin - Taicpu(p).clearop(0); - Taicpu(p).ops:=0; - Taicpu(p).is_jmp:=false; - Taicpu(p).opcode:=A_CMC; - Taicpu(p).condition:=C_NONE; - DebugMsg(SPeepholeOptimization+'JccAdd/Inc/Dec2CmcAdc/Sbb',p); - Taicpu(hp1).ops:=2; - if (Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB) then - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[1]^) - else - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); - Taicpu(hp1).loadconst(0,0); - Taicpu(hp1).opcode:=carryadd_opcode; - result:=true; - exit; - end; + case taicpu(hp1).opcode of + A_INC, + A_ADD: + carryadd_opcode:=A_ADC; + A_DEC, + A_SUB: + carryadd_opcode:=A_SBB; + else + InternalError(2021011001); + end; + + Taicpu(p).clearop(0); + Taicpu(p).ops:=0; + Taicpu(p).is_jmp:=false; + Taicpu(p).opcode:=A_CMC; + Taicpu(p).condition:=C_NONE; + DebugMsg(SPeepholeOptimization+'JccAdd/Inc/Dec2CmcAdc/Sbb',p); + Taicpu(hp1).ops:=2; + if (Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB) then + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[1]^) + else + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); + Taicpu(hp1).loadconst(0,0); + Taicpu(hp1).opcode:=carryadd_opcode; + result:=true; + exit; end else if Taicpu(p).condition in [C_AE,C_NB,C_NC] then begin - if (Taicpu(hp1).opcode=A_INC) or - ((Taicpu(hp1).opcode=A_ADD) and - MatchOptype(Taicpu(hp1),top_const,top_reg) and - (Taicpu(hp1).oper[0]^.val=1) - ) then - carryadd_opcode:=A_ADC; - if (Taicpu(hp1).opcode=A_DEC) or - ((Taicpu(hp1).opcode=A_SUB) and - MatchOptype(Taicpu(hp1),top_const,top_reg) and - (Taicpu(hp1).oper[0]^.val=1) - ) then - carryadd_opcode:=A_SBB; - if carryadd_opcode<>A_NONE then - begin - Taicpu(hp1).ops:=2; - DebugMsg(SPeepholeOptimization+'JccAdd/Inc/Dec2Adc/Sbb',p); - if (Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB) then - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[1]^) - else - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); - Taicpu(hp1).loadconst(0,0); - Taicpu(hp1).opcode:=carryadd_opcode; - RemoveCurrentP(p, hp1); - result:=true; - exit; - end; + case taicpu(hp1).opcode of + A_INC, + A_ADD: + carryadd_opcode:=A_ADC; + A_DEC, + A_SUB: + carryadd_opcode:=A_SBB; + else + InternalError(2021011002); + end; + + Taicpu(hp1).ops:=2; + DebugMsg(SPeepholeOptimization+'JccAdd/Inc/Dec2Adc/Sbb',p); + if (Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB) then + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[1]^) + else + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); + Taicpu(hp1).loadconst(0,0); + Taicpu(hp1).opcode:=carryadd_opcode; + RemoveCurrentP(p, hp1); + result:=true; + exit; end { jcc @@1 setcc tmpreg @@ -5742,312 +5784,323 @@ unit aoptx86; While this increases code size slightly, it makes the code much faster if the jump is unpredictable } - else if not(cs_opt_size in current_settings.optimizerswitches) and - ((((Taicpu(hp1).opcode=A_ADD) or (Taicpu(hp1).opcode=A_SUB)) and - (Taicpu(hp1).oper[0]^.typ=top_const) and - (Taicpu(hp1).oper[1]^.typ=top_reg) and - (Taicpu(hp1).oper[0]^.val=1)) or - ((Taicpu(hp1).opcode=A_INC) or (Taicpu(hp1).opcode=A_DEC)) - ) then - begin - TransferUsedRegs(TmpUsedRegs); - UpdateUsedRegs(TmpUsedRegs, tai(p.next)); - - { search for an available register which is volatile } - regavailable:=false; - for reg in tcpuregisterset do - begin - if (reg in paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption)) and - not(reg in TmpUsedRegs[R_INTREGISTER].GetUsedRegs) and - not(RegInInstruction(newreg(R_INTREGISTER,reg,R_SUBL),hp1)) -{$ifdef i386} - and (reg in [RS_EAX,RS_EBX,RS_ECX,RS_EDX]) -{$endif i386} - then - begin - regavailable:=true; - break; - end; - end; - - if regavailable then - begin - Taicpu(p).clearop(0); - Taicpu(p).ops:=1; - Taicpu(p).is_jmp:=false; - Taicpu(p).opcode:=A_SETcc; - DebugMsg(SPeepholeOptimization+'JccAdd2SetccAdd',p); - Taicpu(p).condition:=inverse_cond(Taicpu(p).condition); - Taicpu(p).loadreg(0,newreg(R_INTREGISTER,reg,R_SUBL)); - - if getsubreg(Taicpu(hp1).oper[1]^.reg)<>R_SUBL then - begin - case getsubreg(Taicpu(hp1).oper[1]^.reg) of - R_SUBW: - hp2:=Taicpu.op_reg_reg(A_MOVZX,S_BW,newreg(R_INTREGISTER,reg,R_SUBL), - newreg(R_INTREGISTER,reg,R_SUBW)); - R_SUBD, - R_SUBQ: - hp2:=Taicpu.op_reg_reg(A_MOVZX,S_BL,newreg(R_INTREGISTER,reg,R_SUBL), - newreg(R_INTREGISTER,reg,R_SUBD)); - else - Internalerror(2020030601); - end; - taicpu(hp2).fileinfo:=taicpu(hp1).fileinfo; - asml.InsertAfter(hp2,p); - end; - if (Taicpu(hp1).opcode=A_INC) or (Taicpu(hp1).opcode=A_DEC) then - begin - Taicpu(hp1).ops:=2; - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^) - end; - Taicpu(hp1).loadreg(0,newreg(R_INTREGISTER,reg,getsubreg(Taicpu(hp1).oper[1]^.reg))); - AllocRegBetween(newreg(R_INTREGISTER,reg,getsubreg(Taicpu(hp1).oper[1]^.reg)),p,hp1,UsedRegs); - end; - end; - end; + else if not(cs_opt_size in current_settings.optimizerswitches) then + begin + { search for an available register which is volatile } + for reg in tcpuregisterset do + begin + if + {$if defined(i386) or defined(i8086)} + { Only use registers whose lowest 8-bits can Be accessed } + (reg in [RS_EAX,RS_EBX,RS_ECX,RS_EDX]) and + {$endif i386 or i8086} + (reg in paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption)) and + not(reg in UsedRegs[R_INTREGISTER].GetUsedRegs) + { We don't need to check if tmpreg is in hp1 or not, because + it will be marked as in use at p (if not, this is + indictive of a compiler bug). } + then + begin + TAsmLabel(symbol).decrefs; + increg := newreg(R_INTREGISTER,reg,R_SUBL); + Taicpu(p).clearop(0); + Taicpu(p).ops:=1; + Taicpu(p).is_jmp:=false; + Taicpu(p).opcode:=A_SETcc; + DebugMsg(SPeepholeOptimization+'JccAdd2SetccAdd',p); + Taicpu(p).condition:=inverse_cond(Taicpu(p).condition); + Taicpu(p).loadreg(0,increg); + + if getsubreg(Taicpu(hp1).oper[1]^.reg)<>R_SUBL then + begin + case getsubreg(Taicpu(hp1).oper[1]^.reg) of + R_SUBW: + begin + tmpreg := newreg(R_INTREGISTER,reg,R_SUBW); + hp2:=Taicpu.op_reg_reg(A_MOVZX,S_BW,increg,tmpreg); + end; + R_SUBD: + begin + tmpreg := newreg(R_INTREGISTER,reg,R_SUBD); + hp2:=Taicpu.op_reg_reg(A_MOVZX,S_BL,increg,tmpreg); + end; + {$ifdef x86_64} + R_SUBQ: + begin + { MOVZX doesn't have a 64-bit variant, because + the 32-bit version implicitly zeroes the + upper 32-bits of the destination register } + hp2:=Taicpu.op_reg_reg(A_MOVZX,S_BL,increg, + newreg(R_INTREGISTER,reg,R_SUBD)); + tmpreg := newreg(R_INTREGISTER,reg,R_SUBQ); + end; + {$endif x86_64} + else + Internalerror(2020030601); + end; + taicpu(hp2).fileinfo:=taicpu(hp1).fileinfo; + asml.InsertAfter(hp2,p); + end + else + tmpreg := increg; + + if (Taicpu(hp1).opcode=A_INC) or (Taicpu(hp1).opcode=A_DEC) then + begin + Taicpu(hp1).ops:=2; + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^) + end; + Taicpu(hp1).loadreg(0,tmpreg); + AllocRegBetween(tmpreg,p,hp1,UsedRegs); + + Result := True; + + { p is no longer a Jcc instruction, so exit } + Exit; + end; + end; + end; + end; - { Detect the following: - jmp<cond> @Lbl1 - jmp @Lbl2 - ... - @Lbl1: - ret + { Detect the following: + jmp<cond> @Lbl1 + jmp @Lbl2 + ... + @Lbl1: + ret - Change to: + Change to: - jmp<inv_cond> @Lbl2 - ret - } - if MatchInstruction(hp1,A_JMP,[]) and (taicpu(hp1).oper[0]^.ref^.refaddr=addr_full) then - begin - hp2:=getlabelwithsym(TAsmLabel(symbol)); - if Assigned(hp2) and SkipLabels(hp2,hp2) and - MatchInstruction(hp2,A_RET,[S_NO]) then - begin - taicpu(p).condition := inverse_cond(taicpu(p).condition); - - { Change label address to that of the unconditional jump } - taicpu(p).loadoper(0, taicpu(hp1).oper[0]^); - - TAsmLabel(symbol).DecRefs; - taicpu(hp1).opcode := A_RET; - taicpu(hp1).is_jmp := false; - taicpu(hp1).ops := taicpu(hp2).ops; - DebugMsg(SPeepholeOptimization+'JccJmpRet2J!ccRet',p); - case taicpu(hp2).ops of - 0: - taicpu(hp1).clearop(0); - 1: - taicpu(hp1).loadconst(0,taicpu(hp2).oper[0]^.val); - else - internalerror(2016041302); + jmp<inv_cond> @Lbl2 + ret + } + if MatchInstruction(hp1,A_JMP,[]) and (taicpu(hp1).oper[0]^.ref^.refaddr=addr_full) then + begin + hp2:=getlabelwithsym(TAsmLabel(symbol)); + if Assigned(hp2) and SkipLabels(hp2,hp2) and + MatchInstruction(hp2,A_RET,[S_NO]) then + begin + taicpu(p).condition := inverse_cond(taicpu(p).condition); + + { Change label address to that of the unconditional jump } + taicpu(p).loadoper(0, taicpu(hp1).oper[0]^); + + TAsmLabel(symbol).DecRefs; + taicpu(hp1).opcode := A_RET; + taicpu(hp1).is_jmp := false; + taicpu(hp1).ops := taicpu(hp2).ops; + DebugMsg(SPeepholeOptimization+'JccJmpRet2J!ccRet',p); + case taicpu(hp2).ops of + 0: + taicpu(hp1).clearop(0); + 1: + taicpu(hp1).loadconst(0,taicpu(hp2).oper[0]^.val); + else + internalerror(2016041302); + end; end; - end; - end; - end; {$ifndef i8086} - if CPUX86_HAS_CMOV in cpu_capabilities[current_settings.cputype] then - begin - { check for - jCC xxx - <several movs> - xxx: - } - l:=0; - GetNextInstruction(p, hp1); - while assigned(hp1) and - CanBeCMOV(hp1) and - { stop on labels } - not(hp1.typ=ait_label) do - begin - inc(l); - GetNextInstruction(hp1,hp1); - end; - if assigned(hp1) then - begin - if FindLabel(tasmlabel(symbol),hp1) then - begin - if (l<=4) and (l>0) then + end + else if CPUX86_HAS_CMOV in cpu_capabilities[current_settings.cputype] then + begin + { check for + jCC xxx + <several movs> + xxx: + } + l:=0; + while assigned(hp1) and + CanBeCMOV(hp1) and + { stop on labels } + not(hp1.typ=ait_label) do + begin + inc(l); + GetNextInstruction(hp1,hp1); + end; + if assigned(hp1) then + begin + if FindLabel(tasmlabel(symbol),hp1) then begin - condition:=inverse_cond(taicpu(p).condition); - GetNextInstruction(p,hp1); - repeat - if not Assigned(hp1) then - InternalError(2018062900); - - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - UpdateUsedRegs(hp1); - GetNextInstruction(hp1,hp1); - until not(CanBeCMOV(hp1)); - - { Remember what hp1 is in case there's multiple aligns to get rid of } - hp2 := hp1; - repeat - if not Assigned(hp2) then - InternalError(2018062910); - - case hp2.typ of - ait_label: - { What we expected - break out of the loop (it won't be a dead label at the top of - a cluster because that was optimised at an earlier stage) } - Break; - ait_align: - { Go to the next entry until a label is found (may be multiple aligns before it) } - begin - hp2 := tai(hp2.Next); - Continue; - end; - else - begin - { Might be a comment or temporary allocation entry } - if not (hp2.typ in SkipInstr) then - InternalError(2018062911); + if (l<=4) and (l>0) then + begin + condition:=inverse_cond(taicpu(p).condition); + GetNextInstruction(p,hp1); + repeat + if not Assigned(hp1) then + InternalError(2018062900); + + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + UpdateUsedRegs(hp1); + GetNextInstruction(hp1,hp1); + until not(CanBeCMOV(hp1)); + + { Remember what hp1 is in case there's multiple aligns to get rid of } + hp2 := hp1; + repeat + if not Assigned(hp2) then + InternalError(2018062910); + + case hp2.typ of + ait_label: + { What we expected - break out of the loop (it won't be a dead label at the top of + a cluster because that was optimised at an earlier stage) } + Break; + ait_align: + { Go to the next entry until a label is found (may be multiple aligns before it) } + begin + hp2 := tai(hp2.Next); + Continue; + end; + else + begin + { Might be a comment or temporary allocation entry } + if not (hp2.typ in SkipInstr) then + InternalError(2018062911); - hp2 := tai(hp2.Next); - Continue; + hp2 := tai(hp2.Next); + Continue; + end; end; - end; - until False; + until False; - { Now we can safely decrement the reference count } - tasmlabel(symbol).decrefs; + { Now we can safely decrement the reference count } + tasmlabel(symbol).decrefs; - DebugMsg(SPeepholeOptimization+'JccMov2CMov',p); + DebugMsg(SPeepholeOptimization+'JccMov2CMov',p); - { Remove the original jump } - RemoveInstruction(p); { Note, the choice to not use RemoveCurrentp is deliberate } + { Remove the original jump } + RemoveInstruction(p); { Note, the choice to not use RemoveCurrentp is deliberate } - GetNextInstruction(hp2, p); { Instruction after the label } + GetNextInstruction(hp2, p); { Instruction after the label } - { Remove the label if this is its final reference } - if (tasmlabel(symbol).getrefs=0) then - StripLabelFast(hp1); + { Remove the label if this is its final reference } + if (tasmlabel(symbol).getrefs=0) then + StripLabelFast(hp1); - if Assigned(p) then - begin - UpdateUsedRegs(p); - result:=true; + if Assigned(p) then + begin + UpdateUsedRegs(p); + result:=true; + end; + exit; end; - exit; - end; - end - else - begin - { check further for - jCC xxx - <several movs 1> - jmp yyy - xxx: - <several movs 2> - yyy: - } - { hp2 points to jmp yyy } - hp2:=hp1; - { skip hp1 to xxx (or an align right before it) } - GetNextInstruction(hp1, hp1); - - if assigned(hp2) and - assigned(hp1) and - (l<=3) and - (hp2.typ=ait_instruction) and - (taicpu(hp2).is_jmp) and - (taicpu(hp2).condition=C_None) and - { real label and jump, no further references to the - label are allowed } - (tasmlabel(symbol).getrefs=1) and - FindLabel(tasmlabel(symbol),hp1) then - begin - l:=0; - { skip hp1 to <several moves 2> } - if (hp1.typ = ait_align) then - GetNextInstruction(hp1, hp1); - - GetNextInstruction(hp1, hpmov2); - - hp1 := hpmov2; - while assigned(hp1) and - CanBeCMOV(hp1) do - begin - inc(l); - GetNextInstruction(hp1, hp1); - end; - { hp1 points to yyy (or an align right before it) } - hp3 := hp1; - if assigned(hp1) and - FindLabel(tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol),hp1) then + end + else + begin + { check further for + jCC xxx + <several movs 1> + jmp yyy + xxx: + <several movs 2> + yyy: + } + { hp2 points to jmp yyy } + hp2:=hp1; + { skip hp1 to xxx (or an align right before it) } + GetNextInstruction(hp1, hp1); + + if assigned(hp2) and + assigned(hp1) and + (l<=3) and + (hp2.typ=ait_instruction) and + (taicpu(hp2).is_jmp) and + (taicpu(hp2).condition=C_None) and + { real label and jump, no further references to the + label are allowed } + (tasmlabel(symbol).getrefs=1) and + FindLabel(tasmlabel(symbol),hp1) then begin - condition:=inverse_cond(taicpu(p).condition); - GetNextInstruction(p,hp1); - repeat - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - UpdateUsedRegs(hp1); - GetNextInstruction(hp1,hp1); - until not(assigned(hp1)) or - not(CanBeCMOV(hp1)); - - condition:=inverse_cond(condition); - hp1 := hpmov2; - { hp1 is now at <several movs 2> } - while Assigned(hp1) and CanBeCMOV(hp1) do - begin - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - UpdateUsedRegs(hp1); - GetNextInstruction(hp1,hp1); - end; + l:=0; + { skip hp1 to <several moves 2> } + if (hp1.typ = ait_align) then + GetNextInstruction(hp1, hp1); + + GetNextInstruction(hp1, hpmov2); + + hp1 := hpmov2; + while assigned(hp1) and + CanBeCMOV(hp1) do + begin + inc(l); + GetNextInstruction(hp1, hp1); + end; + { hp1 points to yyy (or an align right before it) } + hp3 := hp1; + if assigned(hp1) and + FindLabel(tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol),hp1) then + begin + condition:=inverse_cond(taicpu(p).condition); + GetNextInstruction(p,hp1); + repeat + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + UpdateUsedRegs(hp1); + GetNextInstruction(hp1,hp1); + until not(assigned(hp1)) or + not(CanBeCMOV(hp1)); + + condition:=inverse_cond(condition); + hp1 := hpmov2; + { hp1 is now at <several movs 2> } + while Assigned(hp1) and CanBeCMOV(hp1) do + begin + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + UpdateUsedRegs(hp1); + GetNextInstruction(hp1,hp1); + end; - hp1 := p; + hp1 := p; - { Get first instruction after label } - GetNextInstruction(hp3, p); + { Get first instruction after label } + GetNextInstruction(hp3, p); - if assigned(p) and (hp3.typ = ait_align) then - GetNextInstruction(p, p); + if assigned(p) and (hp3.typ = ait_align) then + GetNextInstruction(p, p); - { Don't dereference yet, as doing so will cause - GetNextInstruction to skip the label and - optional align marker. [Kit] } - GetNextInstruction(hp2, hp4); + { Don't dereference yet, as doing so will cause + GetNextInstruction to skip the label and + optional align marker. [Kit] } + GetNextInstruction(hp2, hp4); - DebugMsg(SPeepholeOptimization+'JccMovJmpMov2CMovCMov',hp1); + DebugMsg(SPeepholeOptimization+'JccMovJmpMov2CMovCMov',hp1); - { remove jCC } - RemoveInstruction(hp1); + { remove jCC } + RemoveInstruction(hp1); - { Now we can safely decrement it } - tasmlabel(symbol).decrefs; + { Now we can safely decrement it } + tasmlabel(symbol).decrefs; - { Remove label xxx (it will have a ref of zero due to the initial check } - StripLabelFast(hp4); + { Remove label xxx (it will have a ref of zero due to the initial check } + StripLabelFast(hp4); - { remove jmp } - symbol := taicpu(hp2).oper[0]^.ref^.symbol; + { remove jmp } + symbol := taicpu(hp2).oper[0]^.ref^.symbol; - RemoveInstruction(hp2); + RemoveInstruction(hp2); - { As before, now we can safely decrement it } - tasmlabel(symbol).decrefs; + { As before, now we can safely decrement it } + tasmlabel(symbol).decrefs; - { Remove label yyy (and the optional alignment) if its reference falls to zero } - if tasmlabel(symbol).getrefs = 0 then - StripLabelFast(hp3); + { Remove label yyy (and the optional alignment) if its reference falls to zero } + if tasmlabel(symbol).getrefs = 0 then + StripLabelFast(hp3); - if Assigned(p) then - begin - UpdateUsedRegs(p); - result:=true; - end; - exit; + if Assigned(p) then + begin + UpdateUsedRegs(p); + result:=true; + end; + exit; + end; end; - end; - end; - end; - end; + end; + end; {$endif i8086} + end; + end; end; @@ -7016,12 +7069,14 @@ unit aoptx86; function TX86AsmOptimizer.PostPeepholeOptPush(var p : tai) : Boolean; +{$ifdef x86_64} var hp1, hp2, hp3, hp4, hp5: tai; +{$endif x86_64} begin Result:=false; - hp5:=nil; {$ifdef x86_64} + hp5:=nil; { replace push %rax call procname @@ -7476,7 +7531,8 @@ unit aoptx86; (taicpu(hp1).opcode = A_TEST) and MatchOperand(taicpu(hp1).oper[0]^, taicpu(hp1).oper[1]^) ) ) and - (reg2opsize(taicpu(hp1).oper[1]^.reg) <= reg2opsize(taicpu(p).oper[1]^.reg)) then + (reg2opsize(taicpu(hp1).oper[1]^.reg) <= reg2opsize(taicpu(p).oper[1]^.reg)) and + SuperRegistersEqual(taicpu(p).oper[1]^.reg, taicpu(hp1).oper[1]^.reg) then begin PreMessage := debug_op2str(taicpu(hp1).opcode) + debug_opsize2str(taicpu(hp1).opsize) + ' ' + debug_operstr(taicpu(hp1).oper[0]^) + ',' + debug_regname(taicpu(hp1).oper[1]^.reg) + ' -> ' + debug_op2str(taicpu(hp1).opcode); diff --git a/avx512-0037785/compiler/x86/cgx86.pas b/avx512-0037785/compiler/x86/cgx86.pas index b270ddd59d..a790ccac4f 100644 --- a/avx512-0037785/compiler/x86/cgx86.pas +++ b/avx512-0037785/compiler/x86/cgx86.pas @@ -445,13 +445,17 @@ unit cgx86; procedure tcgx86.make_simple_ref(list:TAsmList;var ref: treference;isdirect:boolean); var +{$ifndef i8086} hreg : tregister; +{$endif i8086} href : treference; -{$ifndef x86_64} +{$ifdef i386} add_hreg: boolean; -{$endif not x86_64} +{$endif i386} begin +{$ifndef i8086} hreg:=NR_NO; +{$endif i8086} { make_simple_ref() may have already been called earlier, and in that case make sure we don't perform the PIC-simplifications twice } if (ref.refaddr in [addr_pic,addr_pic_no_got]) then @@ -1083,7 +1087,9 @@ unit cgx86; procedure tcgx86.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister); var dirref,tmpref : treference; +{$ifndef i8086} tmpreg : TRegister; +{$endif i8086} begin dirref:=ref; @@ -1995,7 +2001,7 @@ unit cgx86; href.scalefactor:=a; list.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[size],href,dst)); end - else if (op in [OP_MUL,OP_IMUL]) and (size in [OS_32,OS_S32,OS_64,OS_S64]) and + else if (op in [OP_MUL,OP_IMUL]) and (size in [OS_16,OS_S16,OS_32,OS_S32,OS_64,OS_S64]) and (a>1) and (a<=maxLongint) and not ispowerof2(int64(a),power) then begin { MUL with overflow checking should be handled specifically in the code generator } @@ -2343,6 +2349,17 @@ unit cgx86; begin if reg2opsize(src) <> dstsize then internalerror(200109226); + { x86 does not have an 8 Bit imul, so do 16 Bit multiplication + we do not need to zero/sign extend as we discard the upper bits anyways } + if (TOpCG2AsmOp[op]=A_IMUL) and (size in [OS_8,OS_S8]) then + begin + { this might only happen if no overflow checking is done } + if cs_check_overflow in current_settings.localswitches then + Internalerror(2021011601); + src:=makeregsize(list,src,OS_16); + dst:=makeregsize(list,dst,OS_16); + dstsize:=S_W; + end; instr:=taicpu.op_reg_reg(TOpCG2AsmOp[op],dstsize,src,dst); list.concat(instr); end; @@ -3220,10 +3237,12 @@ unit cgx86; {$ifdef x86} {$ifndef NOTARGETWIN} +{$ifndef i8086} var href : treference; i : integer; again : tasmlabel; +{$endif i8086} {$endif NOTARGETWIN} {$endif x86} begin diff --git a/avx512-0037785/compiler/x86/cx86mminnr.inc b/avx512-0037785/compiler/x86/cx86mminnr.inc index f4684e66c1..6d2717f644 100644 --- a/avx512-0037785/compiler/x86/cx86mminnr.inc +++ b/avx512-0037785/compiler/x86/cx86mminnr.inc @@ -499,5 +499,5 @@ in_x86_pcmpistrm = in_x86_mm_first+498, in_x86_pcmpistrm_from_mem = in_x86_mm_first+499, in_x86_pcmpgtq = in_x86_mm_first+500, - in_x86_pcmpgtq_from_mem = in_x86_mm_first+501, - in_x86mm_last = in_x86_mm_first+501 + in_x86_pcmpgtq_from_mem = in_x86_mm_first+501 + diff --git a/avx512-0037785/compiler/x86/nx86inl.pas b/avx512-0037785/compiler/x86/nx86inl.pas index 1b9c174d44..c26cbd5a32 100644 --- a/avx512-0037785/compiler/x86/nx86inl.pas +++ b/avx512-0037785/compiler/x86/nx86inl.pas @@ -1144,6 +1144,7 @@ implementation procedure tx86inlinenode.second_fma; +{$ifndef i8086} const op : array[false..true,false..true,s32real..s64real,0..3] of TAsmOp = ( @@ -1178,6 +1179,7 @@ implementation negop3, negproduct, gotmem : boolean; +{$endif i8086} begin {$ifndef i8086} if (cpu_capabilities[current_settings.cputype]*[CPUX86_HAS_FMA,CPUX86_HAS_FMA4])<>[] then @@ -1444,6 +1446,7 @@ implementation procedure tx86inlinenode.second_minmax; +{$ifndef i8086} const oparray : array[false..true,false..true,s32real..s64real] of TAsmOp = ( @@ -1463,6 +1466,7 @@ implementation i : integer; gotmem : boolean; op: TAsmOp; +{$endif i8086} begin {$ifndef i8086} if diff --git a/avx512-0037785/compiler/x86/nx86mat.pas b/avx512-0037785/compiler/x86/nx86mat.pas index 036fb2dc67..19359e2e0a 100644 --- a/avx512-0037785/compiler/x86/nx86mat.pas +++ b/avx512-0037785/compiler/x86/nx86mat.pas @@ -164,10 +164,6 @@ interface procedure tx86unaryminusnode.second_float; - var - reg : tregister; - href : treference; - l1 : tasmlabel; begin secondpass(left); @@ -387,7 +383,10 @@ interface cgsize:=def_cgsize(resultdef); opsize:=TCGSize2OpSize[cgsize]; rega:=newreg(R_INTREGISTER,RS_EAX,cgsize2subreg(R_INTREGISTER,cgsize)); - regd:=newreg(R_INTREGISTER,RS_EDX,cgsize2subreg(R_INTREGISTER,cgsize)); + if cgsize in [OS_8,OS_S8] then + regd:=NR_AH + else + regd:=newreg(R_INTREGISTER,RS_EDX,cgsize2subreg(R_INTREGISTER,cgsize)); location_reset(location,LOC_REGISTER,cgsize); hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false); diff --git a/avx512-0037785/compiler/x86/nx86set.pas b/avx512-0037785/compiler/x86/nx86set.pas index 001ba0fc40..c0caf10b19 100644 --- a/avx512-0037785/compiler/x86/nx86set.pas +++ b/avx512-0037785/compiler/x86/nx86set.pas @@ -420,7 +420,7 @@ implementation start,stop : byte; {Start/stop when range; Stop=element when an element.} end; var - hreg,hreg2, + hreg,{$ifndef i8086} hreg2, {$endif} pleftreg : tregister; opsize : tcgsize; opdef : torddef; diff --git a/avx512-0037785/compiler/x86/rax86.pas b/avx512-0037785/compiler/x86/rax86.pas index 0c077535c2..a0cfa731a0 100644 --- a/avx512-0037785/compiler/x86/rax86.pas +++ b/avx512-0037785/compiler/x86/rax86.pas @@ -1617,8 +1617,6 @@ procedure Tx86Instruction.SetInstructionOpsize; end; end; -var - isBCastMemRef: boolean; begin if opsize<>S_NO then exit; diff --git a/avx512-0037785/compiler/x86_64/aoptcpu.pas b/avx512-0037785/compiler/x86_64/aoptcpu.pas index 5ac6583fd5..0829a8b9c4 100644 --- a/avx512-0037785/compiler/x86_64/aoptcpu.pas +++ b/avx512-0037785/compiler/x86_64/aoptcpu.pas @@ -71,6 +71,8 @@ uses ait_instruction: begin case taicpu(p).opcode of + A_ADD: + Result:=OptPass1ADD(p); A_AND: Result:=OptPass1AND(p); A_IMUL: diff --git a/avx512-0037785/compiler/x86_64/cpuelf.pas b/avx512-0037785/compiler/x86_64/cpuelf.pas index 7c7dc3cdf0..dfea338a74 100644 --- a/avx512-0037785/compiler/x86_64/cpuelf.pas +++ b/avx512-0037785/compiler/x86_64/cpuelf.pas @@ -88,6 +88,8 @@ implementation R_X86_64_TLSDESC_CALL = 35; R_X86_64_TLSDESC = 36; R_X86_64_IRELATIVE = 37; + R_X86_64_GOTPCRELX =41; + R_X86_64_REX_GOTPCRELX =42; R_X86_64_GNU_VTINHERIT = 250; { GNU extension to record C++ vtable hierarchy } R_X86_64_GNU_VTENTRY = 251; { GNU extension to record C++ vtable member usage } @@ -169,6 +171,10 @@ implementation result:=R_X86_64_32S; RELOC_GOTPCREL : result:=R_X86_64_GOTPCREL; + RELOC_GOTPCRELX : + result:=R_X86_64_GOTPCRELX; + RELOC_REX_GOTPCRELX : + result:=R_X86_64_REX_GOTPCRELX; RELOC_PLT32 : result:=R_X86_64_PLT32; RELOC_TPOFF: diff --git a/avx512-0037785/compiler/x86_64/cpupara.pas b/avx512-0037785/compiler/x86_64/cpupara.pas index 7bbb48580c..b35b0a2331 100644 --- a/avx512-0037785/compiler/x86_64/cpupara.pas +++ b/avx512-0037785/compiler/x86_64/cpupara.pas @@ -178,10 +178,13 @@ unit cpupara; cl.typ:=X86_64_INTEGERSI_CLASS; { gcc/clang sign/zero-extend all values to 32 bits, except for _Bool (= Pascal boolean), which is only zero-extended to 8 bits - as per the x86-64 ABI -> do the same } + as per the x86-64 ABI -> do the same + + some testing showed, that this is not true for 8 bit values: + in case of an 8 bit value, it is not zero/sign extended } if not assigned(cl.def) or - not is_pasbool(cl.def) or - (torddef(cl.def).ordtype<>pasbool1) then + not(cl.def.typ=orddef) or + not(torddef(cl.def).ordtype in [uchar,u8bit,s8bit,pasbool1]) then cl.def:=u32inttype; end else diff --git a/avx512-0037785/compiler/x86_64/nx64mat.pas b/avx512-0037785/compiler/x86_64/nx64mat.pas index 8400bee676..74731bccac 100644 --- a/avx512-0037785/compiler/x86_64/nx64mat.pas +++ b/avx512-0037785/compiler/x86_64/nx64mat.pas @@ -43,6 +43,7 @@ implementation uses globtype,constexp, + cutils, aasmdata,defutil, pass_2, ncon, @@ -69,24 +70,8 @@ implementation else op:=OP_SHR; - { special treatment of 32bit values for backwards compatibility } - { mul optimizations require to keep the sign (FK) } - if left.resultdef.size<=4 then - begin - if is_signed(left.resultdef) then - opsize:=OS_S32 - else - opsize:=OS_32; - mask:=31; - end - else - begin - if is_signed(left.resultdef) then - opsize:=OS_S64 - else - opsize:=OS_64; - mask:=63; - end; + opsize:=def_cgsize(resultdef); + mask:=max(resultdef.size,4)*8-1; { load left operators in a register } if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or diff --git a/avx512-0037785/packages/fcl-base/src/bufstream.pp b/avx512-0037785/packages/fcl-base/src/bufstream.pp index 81ae8d377a..2517542e97 100644 --- a/avx512-0037785/packages/fcl-base/src/bufstream.pp +++ b/avx512-0037785/packages/fcl-base/src/bufstream.pp @@ -812,7 +812,7 @@ begin lNewOffset:=FCacheStreamPosition+Offset; end; end; - if lNewOffset>0 then begin + if lNewOffset>=0 then begin FCacheStreamPosition:=lNewOffset; Result:=lNewOffset; end else begin diff --git a/avx512-0037785/packages/fcl-base/src/eventlog.pp b/avx512-0037785/packages/fcl-base/src/eventlog.pp index a72bbd1f93..24492b54ea 100644 --- a/avx512-0037785/packages/fcl-base/src/eventlog.pp +++ b/avx512-0037785/packages/fcl-base/src/eventlog.pp @@ -23,9 +23,10 @@ uses SysUtils,Classes; Type TEventLog = Class; - TLogType = (ltSystem,ltFile); + TLogType = (ltSystem,ltFile,ltStdOut,ltStdErr); TLogCodeEvent = Procedure (Sender : TObject; Var Code : DWord) of Object; TLogCategoryEvent = Procedure (Sender : TObject; Var Code : Word) of Object; + TLogMessageEvent = Procedure (Sender : TObject; EventType : TEventType; Const Msg : String) of Object; TEventLog = Class(TComponent) Private @@ -44,6 +45,7 @@ Type FOnGetCustomCategory : TLogCategoryEvent; FOnGetCustomEventID : TLogCodeEvent; FOnGetCustomEvent : TLogCodeEvent; + FOnLogMessage: TLogMessageEvent; FPaused : Boolean; procedure SetActive(const Value: Boolean); procedure SetIdentification(const Value: String); @@ -52,16 +54,20 @@ Type procedure DeActivateLog; procedure ActivateFileLog; procedure SetFileName(const Value: String); + procedure ActivateIOLog; procedure ActivateSystemLog; function DefaultFileName: String; + function FormatLogMessage(EventType : TEventType; const Msg: String): String; procedure WriteFileLog(EventType : TEventType; const Msg: String); procedure WriteSystemLog(EventType: TEventType; const Msg: String); + procedure WriteIOLog(EventType: TEventType; const Msg: String; var OutFile: TextFile); procedure DeActivateFileLog; procedure DeActivateSystemLog; procedure CheckIdentification; Procedure DoGetCustomEventID(Var Code : DWord); Procedure DoGetCustomEventCategory(Var Code : Word); Procedure DoGetCustomEvent(Var Code : DWord); + Procedure DoLogMessage(EventType : TEventType; const Msg: String); Protected Procedure CheckInactive; Procedure EnsureActive; @@ -101,6 +107,7 @@ Type Property OnGetCustomCategory : TLogCategoryEvent Read FOnGetCustomCategory Write FOnGetCustomCategory; Property OnGetCustomEventID : TLogCodeEvent Read FOnGetCustomEventID Write FOnGetCustomEventID; Property OnGetCustomEvent : TLogCodeEvent Read FOnGetCustomEvent Write FOnGetCustomEvent; + Property OnLogMessage : TLogMessageEvent read FOnLogMessage write FOnLogMessage; Property Paused : Boolean Read FPaused Write FPaused; End; @@ -114,6 +121,8 @@ Resourcestring SLogDebug = 'Debug'; SLogCustom = 'Custom (%d)'; SErrLogFailedMsg = 'Failed to log entry (Error: %s)'; + SErrLogOpenStdOut = 'Standard Output not available for logging'; + SErrLogOpenStdErr = 'Standard Error not available for logging'; implementation @@ -201,20 +210,31 @@ begin Case FlogType of ltFile : WriteFileLog(EventType,Msg); ltSystem : WriteSystemLog(EventType,Msg); + ltStdOut : WriteIOLog(EventType,Msg,StdOut); + ltStdErr : WriteIOLog(EventType,Msg,StdErr); end; + DoLogMessage(EventType, Msg); end; -procedure TEventLog.WriteFileLog(EventType : TEventType; const Msg : String); - +function TEventLog.FormatLogMessage(EventType : TEventType; const Msg: String): String; Var - S,TS,T : String; + TS,T : String; begin If FTimeStampFormat='' then FTimeStampFormat:='yyyy-mm-dd hh:nn:ss.zzz'; TS:=FormatDateTime(FTimeStampFormat,Now); T:=EventTypeToString(EventType); - S:=Format('%s [%s %s] %s%s',[Identification,TS,T,Msg,LineEnding]); + Result:=Format('%s [%s %s] %s',[Identification,TS,T,Msg]); +end; + +procedure TEventLog.WriteFileLog(EventType : TEventType; const Msg : String); + +Var + S : String; + +begin + S:=FormatLogMessage(EventType, Msg)+LineEnding; try FStream.WriteBuffer(S[1],Length(S)); S:=''; @@ -226,6 +246,11 @@ begin Raise ELogError.CreateFmt(SErrLogFailedMsg,[S]); end; +procedure TEventLog.WriteIOLog(EventType: TEventType; const Msg: String; var OutFile: TextFile); +begin + Writeln(OutFile,FormatLogMessage(EventType,Msg)); +end; + procedure TEventLog.Log(const Fmt: String; Args: array of const); begin Log(Format(Fmt,Args)); @@ -249,6 +274,8 @@ begin Case FLogType of ltFile : ActivateFileLog; ltSystem : ActivateSystemLog; + ltStdOut, + ltStdErr : ActivateIOLog; end; end; @@ -258,6 +285,8 @@ begin Case FLogType of ltFile : DeActivateFileLog; ltSystem : DeActivateSystemLog; + { nothing to do here } + ltStdOut,ltStdErr : ; end; end; @@ -279,6 +308,24 @@ begin FStream.Seek(0,soFromEnd); end; +Procedure TEventLog.ActivateIOLog; + +var + errmsg: String; + m: LongInt; + +begin + if FLogtype = ltStdOut then begin + m := TextRec(StdOut).Mode; + errmsg := SErrLogOpenStdOut; + end else begin + m := TextRec(StdErr).Mode; + errmsg := SErrLogOpenStdErr; + end; + if (m <> fmOutput) and (m <> fmAppend) then + raise ELogError.Create(errmsg); +end; + Procedure TEventLog.DeActivateFileLog; begin @@ -354,6 +401,13 @@ begin FOnGetCustomEvent(Self,Code); end; +Procedure TEventLog.DoLogMessage(EventType : TEventType; const Msg: String); + +begin + If Assigned(FOnLogMessage) then + FOnLogMessage(Self,EventType,Msg); +end; + destructor TEventLog.Destroy; begin diff --git a/avx512-0037785/packages/fcl-db/src/sqldb/interbase/ibconnection.pp b/avx512-0037785/packages/fcl-db/src/sqldb/interbase/ibconnection.pp index 35fa20d25a..d145066788 100644 --- a/avx512-0037785/packages/fcl-db/src/sqldb/interbase/ibconnection.pp +++ b/avx512-0037785/packages/fcl-db/src/sqldb/interbase/ibconnection.pp @@ -92,7 +92,8 @@ type procedure GetFloat(CurrBuff, Buffer : pointer; Size : Byte); procedure SetFloat(CurrBuff: pointer; Dbl: Double; Size: integer); - procedure CheckError(ProcName : string; Status : PISC_STATUS); + procedure CheckError(ProcName : string; Status : PISC_STATUS;IgnoreErrors : Array of Longint); overload; + procedure CheckError(ProcName : string; Status : PISC_STATUS); overload; procedure SetParameters(cursor : TSQLCursor; aTransation : TSQLTransaction; AParams : TParams); procedure FreeSQLDABuffer(var aSQLDA : PXSQLDA); function IsDialectStored: boolean; @@ -170,6 +171,12 @@ const INVALID_DATA = -1; procedure TIBConnection.CheckError(ProcName : string; Status : PISC_STATUS); + +begin + CheckError(ProcName,Status,[]); +end; + +procedure TIBConnection.CheckError(ProcName : string; Status : PISC_STATUS; IgnoreErrors : Array of Longint); var i,ErrorCode : longint; Msg, SQLState : string; @@ -181,6 +188,10 @@ begin if ((Status[0] = 1) and (Status[1] <> 0)) then begin ErrorCode := Status[1]; + if Length(IgnoreErrors)>0 then + for I in IgnoreErrors do + if I=ErrorCode then + Exit; {$IFDEF LinkDynamically} if assigned(fb_sqlstate) then // >= Firebird 2.5 begin @@ -967,7 +978,8 @@ begin if FSelectable and (CursorName<>'') then begin if isc_dsql_free_statement(@Status, @StatementHandle, DSQL_close)<>0 then - CheckError('Close Cursor', Status); // Ignore this, it can already be closed. + // If transaction was closed (keepOpenOnCommit, then the cursor is already closed. + CheckError('Close Cursor', Status, [335544577]); end; end; end; diff --git a/avx512-0037785/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc b/avx512-0037785/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc index fe5858050b..3aff95a893 100644 --- a/avx512-0037785/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc +++ b/avx512-0037785/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc @@ -1058,7 +1058,7 @@ begin Result := 0 else Result := EncodeDate(EY, EM, ED); - Result := ComposeDateTime(Result, EncodeTime(EH, EN, ES, EMS)); + Result := ComposeDateTime(Result, EncodeTimeInterval(EH, EN, ES, EMS)); end; function TConnectionName.InternalStrToTime(C: pchar; Len: integer): TDateTime; diff --git a/avx512-0037785/packages/fcl-db/src/sqldb/sqldb.pp b/avx512-0037785/packages/fcl-db/src/sqldb/sqldb.pp index 88aca65cae..3118e0f545 100644 --- a/avx512-0037785/packages/fcl-db/src/sqldb/sqldb.pp +++ b/avx512-0037785/packages/fcl-db/src/sqldb/sqldb.pp @@ -802,6 +802,7 @@ type Property Proxy : TSQLConnection Read FProxy; Published Property ConnectorType : String Read FConnectorType Write SetConnectorType; + Property Port; end; TSQLConnectionClass = Class of TSQLConnection; @@ -1197,8 +1198,12 @@ end; procedure TCustomSQLStatement.DeAllocateCursor; begin - if Assigned(FCursor) and Assigned(Database) then - DataBase.DeAllocateCursorHandle(FCursor); + if Assigned(FCursor) then + begin + if Assigned(Database) then + DataBase.DeAllocateCursorHandle(FCursor); + FreeAndNil(FCursor); + end; end; function TCustomSQLStatement.ExpandMacros( OrigSQL : String ) : String; @@ -1515,6 +1520,7 @@ begin end; finally; DeAllocateCursorHandle(Cursor); + FreeAndNil(Cursor); end; end; diff --git a/avx512-0037785/packages/fcl-net/src/netdb.pp b/avx512-0037785/packages/fcl-net/src/netdb.pp index 583d3e899b..b945990e69 100644 --- a/avx512-0037785/packages/fcl-net/src/netdb.pp +++ b/avx512-0037785/packages/fcl-net/src/netdb.pp @@ -84,11 +84,37 @@ Const MaxRecursion = 10; MaxIP4Mapped = 10; + { from http://www.iana.org/assignments/dns-parameters } + DNSQRY_A = 1; // name to IP address + DNSQRY_AAAA = 28; // name to IP6 address + DNSQRY_A6 = 38; // name to IP6 (new) + DNSQRY_PTR = 12; // IP address to name + DNSQRY_MX = 15; // name to MX + DNSQRY_TXT = 16; // name to TXT + DNSQRY_CNAME = 5; + DNSQRY_SOA = 6; + DNSQRY_NS = 2; + DNSQRY_SRV = 33; + + // Flags 1 + QF_QR = $80; + QF_OPCODE = $78; + QF_AA = $04; + QF_TC = $02; // Truncated. + QF_RD = $01; + + // Flags 2 + QF_RA = $80; + QF_Z = $70; + QF_RCODE = $0F; + var EtcPath: string; {$endif FPC_USE_LIBC} Type + TDNSRcode = (rcNoError, rcFormatError,rcServFail,rcNXDomain, + rcNotImpl,rcRefused,rcReserved,rcInvalid); TDNSServerArray = Array of THostAddr; TServiceEntry = record Name : String; @@ -134,6 +160,66 @@ Type end; {$ifndef FPC_USE_LIBC} + +Type + TPayLoad = Array[0..511] of Byte; + TPayLoadTCP = Array[0 .. 65535] of Byte; + + TDNSHeader = packed Record + id : Array[0..1] of Byte; + flags1 : Byte; + flags2 : Byte; + qdcount : word; + ancount : word; + nscount : word; + arcount : word; + end; + + TQueryData = packed Record + h: TDNSHeader; + Payload : TPayLoad; + end; + + TQueryDataLength = packed record + length: Word; + hpl: TQueryData; + end; + + TQueryDataLengthTCP = packed Record + length: Word; + h: TDNSHeader; + Payload : TPayLoadTCP; + end; + + PRRData = ^TRRData; + TRRData = Packed record // RR record + Atype : Word; // Answer type + AClass : Word; + TTL : Cardinal; + RDLength : Word; + end; + + TRRNameData = packed record + RRName : ShortString; + RRMeta : TRRData; + RDataSt : Word; + end; + TRRNameDataArray = array of TRRNameData; + + TDNSDomainName = ShortString; + TDNSRR_SOA = packed record + mname, rname: TDNSDomainName; + serial,refresh,retry,expire,min: Cardinal; + end; + TDNSRR_MX = packed record + preference: Word; + exchange: TDNSDomainName; + end; + TDNSRR_SRV = packed record + priority, weight, port: Word; + target: TDNSDomainName; + end; + Var DNSServers : TDNSServerArray; DNSOptions : String; @@ -189,6 +275,82 @@ Function GetProtocolByNumber(proto: Integer; Var H : TProtocolEntry) : boolean; Function ProcessHosts(FileName : String) : PHostListEntry; Function FreeHostsList(var List : PHostListEntry) : Integer; Procedure HostsListToArray(var List : PHostListEntry; Var Hosts : THostEntryArray; FreeList : Boolean); + +Procedure CheckResolveFile; +Function Query(Resolver : Integer; Var Qry,Ans : TQueryData; QryLen : Integer; Var AnsLen : Integer) : Boolean; +function QueryTCP(Resolver : Integer; Var Qry: TQueryDataLength; + var Ans: TQueryDataLengthTCP; QryLen : Integer; Var AnsLen : Integer) : Boolean; +Function BuildPayLoad(Var Q : TQueryData; Name : String; RR : Word; QClass : Word) : Integer; +Function BuildPayLoadTCP(Var Q : TQueryDataLength; Name : String; RR : Word; QClass : Word) : Integer; + +Function SkipAnsQueries(Var Ans : TQueryData; L : Integer) : integer; +Function SkipAnsQueries(Var Ans : TQueryDataLengthTCP; L : Integer) : integer; + +function stringfromlabel(pl: TPayLoad; var start: Integer): string; +function stringfromlabel(pl: TPayLoadTCP; var start: Integer): string; +Function CheckAnswer(Const Qry : TDNSHeader; Var Ans : TDNSHeader) : Boolean; +function IsValidAtype(atype: Word): Boolean; + +function IsTruncated(R: TDNSHeader): Boolean; +function GetRcode(R: TDNSHeader): TDNSRcode; +function GetFixlenStr(pl: TPayLoad; startidx: Cardinal; len: Byte; + out res: ShortString): Byte; +function GetFixlenStr(pl: TPayLoadTCP; startidx: Cardinal; len: Byte; + out res: ShortString): Byte; + +function NextNameRR(const pl: TPayLoadTCP; start: Word; + out RRName: TRRNameData): Boolean; +function NextNameRR(const pl: TPayLoad; start: Word; + out RRName: TRRNameData): Boolean; + +function GetRRrecords(const pl: TPayloadTCP; var Start: Word; Count: Word): + TRRNameDataArray; +function GetRRrecords(const pl: TPayload; var Start: Word; Count: Word): + TRRNameDataArray; + +function DnsLookup(dn: String; qtype: Word; out Ans: TQueryData; + out AnsLen: Longint): Boolean; +function DnsLookup(dn: String; qtype: Word; out Ans: TQueryDataLengthTCP; + out AnsLen: Longint): Boolean; + +function DNSRRGetA(const RR: TRRNameData; const pl: TPayLoadTCP; + out IP: THostAddr): Boolean; +function DNSRRGetA(const RR: TRRNameData; const pl: TPayLoad; + out IP: THostAddr): Boolean; +function DNSRRGetCNAME(const RR: TRRNameData; const pl: TPayLoad; + out cn: TDNSDomainName): Boolean; +function DNSRRGetCNAME(const RR: TRRNameData; const pl: TPayLoadTCP; + out cn: TDNSDomainName): Boolean; +function DNSRRGetAAAA(const RR: TRRNameData; const pl: TPayLoadTCP; + out IP: THostAddr6): Boolean; +function DNSRRGetAAAA(const RR: TRRNameData; const pl: TPayLoad; + out IP: THostAddr6): Boolean; +function DNSRRGetNS(const RR: TRRNameData; const pl: TPayLoadTCP; + out NSName: TDNSDomainName): Boolean; +function DNSRRGetNS(const RR: TRRNameData; const pl: TPayLoad; + out NSName: TDNSDomainName): Boolean; +function DNSRRGetSOA(const RR: TRRNameData; const pl: TPayLoadTCP; + out dnssoa: TDNSRR_SOA): Boolean; +function DNSRRGetSOA(const RR: TRRNameData; const pl: TPayLoad; + out dnssoa: TDNSRR_SOA): Boolean; +function DNSRRGetText(const RR: TRRNameData; const pl: TPayLoad; + out dnstext: AnsiString): Boolean; +function DNSRRGetText(const RR: TRRNameData; const pl: TPayLoadTCP; + out dnstext: AnsiString): Boolean; +function DNSRRGetMX(const RR: TRRNameData; const pl: TPayLoadTCP; + out MX: TDNSRR_MX): Boolean; +function DNSRRGetMX(const RR: TRRNameData; const pl: TPayLoad; + out MX: TDNSRR_MX): Boolean; +function DNSRRGetPTR(const RR: TRRNameData; const pl: TPayLoadTCP; + out ptr: TDNSDomainName): Boolean; +function DNSRRGetPTR(const RR: TRRNameData; const pl: TPayLoad; + out ptr: TDNSDomainName): Boolean; +function DNSRRGetSRV(const RR: TRRNameData; const pl: TPayload; + out srv: TDNSRR_SRV): Boolean; +function DNSRRGetSRV(const RR: TRRNameData; const pl: TPayloadTCP; + out srv: TDNSRR_SRV): Boolean; + + {$endif FPC_USE_LIBC} Implementation @@ -201,54 +363,14 @@ uses sysutils; {$ifndef FPC_USE_LIBC} +type + TTCPSocketResult = (srTimeout,srPartial,srSocketClose,srOK); + var DefaultDomainListArr : array of string; NDots: Integer; -const - { from http://www.iana.org/assignments/dns-parameters } - DNSQRY_A = 1; // name to IP address - DNSQRY_AAAA = 28; // name to IP6 address - DNSQRY_A6 = 38; // name to IP6 (new) - DNSQRY_PTR = 12; // IP address to name - DNSQRY_MX = 15; // name to MX - DNSQRY_TXT = 16; // name to TXT - DNSQRY_CNAME = 5; - - // Flags 1 - QF_QR = $80; - QF_OPCODE = $78; - QF_AA = $04; - QF_TC = $02; // Truncated. - QF_RD = $01; - - // Flags 2 - QF_RA = $80; - QF_Z = $70; - QF_RCODE = $0F; - - -Type - TPayLoad = Array[0..511] of Byte; - TQueryData = packed Record - id : Array[0..1] of Byte; - flags1 : Byte; - flags2 : Byte; - qdcount : word; - ancount : word; - nscount : word; - arcount : word; - Payload : TPayLoad; - end; - - PRRData = ^TRRData; - TRRData = Packed record // RR record - Atype : Word; // Answer type - AClass : Word; - TTL : Cardinal; - RDLength : Word; - end; { --------------------------------------------------------------------- Some Parsing routines @@ -685,9 +807,10 @@ Var begin Result:=-1; - If length(Name)>506 then + If (Length(Name) = 0) or (length(Name)>506) then Exit; - Result:=0; + + Result:=0; P:=@Q.Payload[0]; Repeat L:=Pos('.',Name); @@ -695,6 +818,17 @@ begin S:=Length(Name) else S:=L-1; + // empty label is invalid, unless it's a dot at the end. + if (S = 0) then + begin + if (Length(Name) > 0) then + begin + Result := -1; + exit; + end + else + break; // empty label at end, break out for final 0 length byte. + end; P[Result]:=S; Move(Name[1],P[Result+1],S); Inc(Result,S+1); @@ -710,7 +844,23 @@ begin Inc(Result,2); end; +{Construct a TCP query payload from the given name, rr and qclass. The + principal difference between the TCP and UDP payloads is the two-octet + length field in the TCP payload. The UDP payload has no length field. + See RFC-1035, section 4.2.2. + + Returns the length of the constructed payload, which doesn't include + the header or the length field.} +function BuildPayLoadTCP(var Q: TQueryDataLength; Name: String; RR: Word; + QClass: Word): Integer; +var + l: Word; +begin + l := BuildPayLoad(Q.hpl, Name, RR, QClass); + Q.length := htons(l + SizeOf(Q.hpl.h)); + Result := l; +end; Function NextRR(Const PayLoad : TPayLoad;Var Start : LongInt; AnsLen : LongInt; Var RR : TRRData) : Boolean; @@ -783,9 +933,8 @@ end; { --------------------------------------------------------------------- QueryData handling functions ---------------------------------------------------------------------} - -Function CheckAnswer(Const Qry : TQueryData; Var Ans : TQueryData) : Boolean; +function CheckAnswer(const Qry: TDNSHeader; var Ans: TDNSHeader): Boolean; begin Result:=False; With Ans do @@ -797,7 +946,7 @@ begin If (Flags1 and QF_QR)=0 then exit; if (Flags1 and QF_OPCODE)<>0 then - exit; + exit; if (Flags2 and QF_RCODE)<>0 then exit; // Number of answers ? @@ -808,6 +957,586 @@ begin end; end; +{ + Check that Atype is valid. These are the DNSQRY_? params we support. See the + definitions at the top of this unit for the names. + Deliberately excluding axfr (252), mailb (253), maila (254), and * (255). +} +function IsValidAtype(atype: Word): Boolean; +begin + Result := False; + case atype of + 1 .. 16, 28, 33: Result := True; + end; +end; + +function IsTruncated(R: TDNSHeader): Boolean; +begin + Result := ((R.flags1 and QF_TC) > 0); +end; + +function GetRcode(R: TDNSHeader): TDNSRcode; +var + rcode_n: Byte; +begin + rcode_n := (R.flags2 and QF_RCODE); + case rcode_n of + 0: Result := rcNoError; + 1: Result := rcFormatError; + 2: Result := rcServFail; + 3: Result := rcNXDomain; + 4: Result := rcNotImpl; + 5: Result := rcRefused; + 6 .. 15: Result := rcReserved; + else + Result := rcInvalid; + end; +end; + +function GetFixlenStr(pl: TPayLoad; startidx: Cardinal; len: Byte; out + res: ShortString): Byte; +begin + Result := 0; + res := ''; + if (startidx + len) > Length(pl) then exit; + SetLength(res, len); + Move(pl[startidx], res[1], len); + Result := len; +end; + +function GetFixlenStr(pl: TPayLoadTCP; startidx: Cardinal; len: Byte; + out res: ShortString): Byte; +begin + Result := 0; + res := ''; + if (startidx + len) > Length(pl) then exit; + SetLength(res, len); + Move(pl[startidx], res[1], len); + Result := len; +end; + +function NextNameRR(const pl: TPayLoadTCP; start: Word; out RRName: TRRNameData + ): Boolean; +var + I : Integer; + PA : PRRData; + +begin + Result:=False; + I:=Start; + if (Length(pl) - I) < (SizeOf(TRRData)+2) then exit; + RRName.RRName := stringfromlabel(pl, I); + if (Length(pl) - I) < (SizeOf(TRRData)) then exit; + + PA:=PRRData(@pl[I]); + RRName.RRMeta := PA^; + RRName.RRMeta.AClass := NToHs(RRName.RRMeta.AClass); + RRName.RRMeta.Atype := NToHs(RRName.RRMeta.Atype); + if not IsValidAtype(RRName.RRMeta.Atype) then + exit; + RRName.RRMeta.RDLength := NToHs(RRName.RRMeta.RDLength); + RRName.RRMeta.TTL := NToHl(RRName.RRMeta.TTL); + RRName.RDataSt := I+SizeOf(TRRData); + // verify that start + rdlength is within the buffer boundary. + if RRName.RDataSt + RRName.RRMeta.RDLength > Length(pl) then exit; + Result := True; +end; + +function NextNameRR(const pl: TPayLoad; start: Word; out RRName: TRRNameData + ): Boolean; +var + I : Integer; + PA : PRRData; + +begin + Result:=False; + I:=Start; + if (Length(pl) - I) < (SizeOf(TRRData)+2) then exit; + RRName.RRName := stringfromlabel(pl, I); + if (Length(pl) - I) < (SizeOf(TRRData)) then exit; + + PA:=PRRData(@pl[I]); + RRName.RRMeta := PA^; + RRName.RRMeta.AClass := NToHs(RRName.RRMeta.AClass); + RRName.RRMeta.Atype := NToHs(RRName.RRMeta.Atype); + if not IsValidAtype(RRName.RRMeta.Atype) then + exit; + + RRName.RRMeta.RDLength := NToHs(RRName.RRMeta.RDLength); + RRName.RRMeta.TTL := NToHl(RRName.RRMeta.TTL); + RRName.RDataSt := I+SizeOf(TRRData); + // verify that start + rdlength is within the buffer boundary. + if RRName.RDataSt + RRName.RRMeta.RDLength > Length(pl) then exit; + Result := True; +end; + +function GetRRrecords(const pl: TPayloadTCP; var Start: Word; Count: Word + ): TRRNameDataArray; +var + I, Total: Word; + B: Boolean; + RRN: TRRNameData; + +begin + I:=0; + Total := 0; + SetLength(Result,Count); + while (I < Count) do + begin + B := NextNameRR(pl, Start, RRN); + if not B then break; + Inc(Total); + Result[I] := RRN; + Inc(I); + Start := RRN.RDataSt+RRN.RRMeta.RDLength; + end; + if Total < Count then SetLength(Result,Total); +end; + +function GetRRrecords(const pl: TPayload; var Start: Word; Count: Word + ): TRRNameDataArray; +var + I, Total: Word; + B: Boolean; + RRN: TRRNameData; + +begin + I:=0; + Total := 0; + SetLength(Result,Count); + while (I < Count) do + begin + B := NextNameRR(pl, Start, RRN); + if not B then break; + Inc(Total); + Result[I] := RRN; + Inc(I); + Start := RRN.RDataSt+RRN.RRMeta.RDLength; + end; + if Total < Count then SetLength(Result,Total); +end; + +function DnsLookup(dn: String; qtype: Word; out Ans: TQueryData; out + AnsLen: Longint): Boolean; +var + Qry: TQueryData; + QryLen: Longint; + idx: Word; +begin + Result := False; + AnsLen := -2; + + CheckResolveFile; + if Length(DNSServers) = 0 then + exit; + + QryLen := BuildPayLoad(Qry, dn, qtype, 1); + if QryLen <= 0 then exit; + + AnsLen := -1; + { Try the query at each configured resolver in turn, until one of them + returns an answer. We check for AnsLen > -1 because we need to distinguish + between failure to connect and the server saying it doesn't know or can't + answer. If AnsLen = -1 then we failed to connect. If AnsLen >= 0 but qr + = False, then we connected but the server returned an error code.} + idx := 0; + repeat + Result := Query(idx,Qry,Ans,QryLen,AnsLen); + Inc(idx); + until (idx > High(DNSServers)) or (Result = True) or (AnsLen >= 0); +end; + +function DnsLookup(dn: String; qtype: Word; out Ans: TQueryDataLengthTCP; out + AnsLen: Longint): Boolean; +var + Qry: TQueryDataLength; + QryLen: Longint; + idx: Word; + +begin + Result := False; + AnsLen := -2; + + CheckResolveFile; + if Length(DNSServers) = 0 then + exit; + + QryLen:=BuildPayLoadTCP(Qry, dn, qtype, 1); + if QryLen <= 0 then exit; + AnsLen := -1; + + { Try the query at each configured resolver in turn, until one of them + returns an answer. We check for AnsLen > -1 because we need to distinguish + between failure to connect and the server saying it doesn't know or can't + answer. If AnsLen = -1 then we failed to connect. If AnsLen >= 0 but qr + = False, then we connected but the server returned an error code.} + idx := 0; + repeat + Result := QueryTCP(idx,Qry,Ans,QryLen,AnsLen); + Inc(idx); + until (idx > High(DNSServers)) or (Result = True) or (AnsLen >= 0); +end; + +function DNSRRGetA(const RR: TRRNameData; const pl: TPayLoadTCP; out + IP: THostAddr): Boolean; +begin + IP.s_addr := 0; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_A then exit; + if (Length(pl) - RR.RDataSt) < 4 then exit; + Move(pl[RR.RDataSt], IP, SizeOf(THostAddr)); + IP.s_addr := NToHl(IP.s_addr); + Result := True; +end; + +function DNSRRGetA(const RR: TRRNameData; const pl: TPayLoad; out IP: THostAddr + ): Boolean; +begin + IP.s_addr := 0; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_A then exit; + if (Length(pl) - RR.RDataSt) < 4 then exit; + Move(pl[RR.RDataSt], IP, SizeOf(THostAddr)); + IP.s_addr := NToHl(IP.s_addr); + Result := True; +end; + +function DNSRRGetCNAME(const RR: TRRNameData; const pl: TPayLoad; out + cn: TDNSDomainName): Boolean; +var + n: Integer; +begin + Result := False; + cn := ''; + if RR.RRMeta.Atype <> DNSQRY_CNAME then exit; + n := RR.RDataSt; + if (RR.RDataSt + RR.RRMeta.RDLength) > Length(pl) then exit; + cn := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetCNAME(const RR: TRRNameData; const pl: TPayLoadTCP; out + cn: TDNSDomainName): Boolean; +var + n: Integer; +begin + Result := False; + cn := ''; + if RR.RRMeta.Atype <> DNSQRY_CNAME then exit; + n := RR.RDataSt; + if (n + RR.RRMeta.rdlength) > Length(pl) then exit; + cn := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetAAAA(const RR: TRRNameData; const pl: TPayLoadTCP; out + IP: THostAddr6): Boolean; +begin + IP.s6_addr32[0] := 0; + IP.s6_addr32[1] := 0; + IP.s6_addr32[2] := 0; + IP.s6_addr32[3] := 0; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_AAAA then exit; + if (RR.RDataSt + SizeOf(THostAddr6)) > Length(pl) then exit; + Move(pl[RR.RDataSt],IP,SizeOf(THostAddr6)); + Result := True; +end; + +function DNSRRGetAAAA(const RR: TRRNameData; const pl: TPayLoad; out + IP: THostAddr6): Boolean; +begin + IP.s6_addr32[0] := 0; + IP.s6_addr32[1] := 0; + IP.s6_addr32[2] := 0; + IP.s6_addr32[3] := 0; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_AAAA then exit; + if (RR.RDataSt + SizeOf(THostAddr6)) > Length(pl) then exit; + Move(pl[RR.RDataSt],IP,SizeOf(THostAddr6)); + Result := True; +end; + +function DNSRRGetNS(const RR: TRRNameData; const pl: TPayLoadTCP; out + NSName: TDNSDomainName): Boolean; +var + n: LongInt; +begin + NSName := ''; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_NS then exit; + if (RR.RDataSt + RR.RRMeta.RDLength) > Length(pl) then exit; + n := RR.RDataSt; + NSName := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetNS(const RR: TRRNameData; const pl: TPayLoad; out + NSName: TDNSDomainName): Boolean; +var + n: LongInt; +begin + NSName := ''; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_NS then exit; + if (RR.RDataSt + RR.RRMeta.RDLength) > Length(pl) then exit; + n := RR.RDataSt; + NSName := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetSOA(const RR: TRRNameData; const pl: TPayLoadTCP; out + dnssoa: TDNSRR_SOA): Boolean; +var + idx: Integer; +begin + // can't trust the counts we've been given, so check that we never + // exceed the end of the payload buffer. + idx := RR.RDataSt; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_SOA then exit; + dnssoa.mname := stringfromlabel(pl, idx); + if idx >= Length(pl) then exit; + + dnssoa.rname := stringfromlabel(pl, idx); + + if (idx + (SizeOf(Cardinal) * 5)) > Length(pl) then exit; + Move(pl[idx],dnssoa.serial,SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.refresh, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.retry, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.expire, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.min, SizeOf(Cardinal)); + Result := True; + dnssoa.serial := NToHl(dnssoa.serial); + dnssoa.min := NToHl(dnssoa.min); + dnssoa.expire := NToHl(dnssoa.expire); + dnssoa.refresh := NToHl(dnssoa.refresh); + dnssoa.retry := NToHl(dnssoa.retry); +end; + +function DNSRRGetSOA(const RR: TRRNameData; const pl: TPayLoad; out + dnssoa: TDNSRR_SOA): Boolean; +var + idx: Integer; +begin + // can't trust the counts we've been given, so check that we never + // exceed the end of the payload buffer. + idx := RR.RDataSt; + Result := False; + if RR.RRMeta.Atype <> DNSQRY_SOA then exit; + dnssoa.mname := stringfromlabel(pl, idx); + if idx >= Length(pl) then exit; + + dnssoa.rname := stringfromlabel(pl, idx); + + if (idx + (SizeOf(Cardinal) * 5)) > Length(pl) then exit; + Move(pl[idx],dnssoa.serial,SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.refresh, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.retry, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.expire, SizeOf(Cardinal)); + Inc(idx, SizeOf(Cardinal)); + Move(pl[idx], dnssoa.min, SizeOf(Cardinal)); + Result := True; + dnssoa.serial := NToHl(dnssoa.serial); + dnssoa.min := NToHl(dnssoa.min); + dnssoa.expire := NToHl(dnssoa.expire); + dnssoa.refresh := NToHl(dnssoa.refresh); + dnssoa.retry := NToHl(dnssoa.retry); +end; + +function DNSRRGetText(const RR: TRRNameData; const pl: TPayLoad; out + dnstext: AnsiString): Boolean; +var + wrk: ShortString; + idx: LongInt; + l: Byte; +begin + Result := False; + dnstext := ''; + if RR.RRMeta.Atype <> DNSQRY_TXT then exit; + wrk := ''; + + idx := RR.RDataSt; + if (Length(pl) - idx) < 2 then exit; + + repeat + l := GetFixlenStr(pl, idx+1, pl[idx], wrk); + if l = 0 then exit; // count would send us past end of buffer + dnstext := dnstext + wrk; + Inc(idx, l+1); + until (idx >= (RR.RDataSt + RR.RRMeta.RDLength)) or ((Length(pl) - idx) < 2); + Result := True; +end; + +function DNSRRGetText(const RR: TRRNameData; const pl: TPayLoadTCP; out + dnstext: AnsiString): Boolean; +var + wrk: ShortString; + idx: LongInt; + l: Byte; +begin + Result := False; + dnstext := ''; + if RR.RRMeta.Atype <> DNSQRY_TXT then exit; + wrk := ''; + + idx := RR.RDataSt; + if (Length(pl) - idx) < 2 then exit; + + repeat + l := GetFixlenStr(pl, idx+1, pl[idx], wrk); + if l = 0 then exit; // count would send us past end of buffer + dnstext := dnstext + wrk; + Inc(idx, l+1); + until (idx >= (RR.RDataSt + RR.RRMeta.RDLength)) or ((Length(pl) - idx) < 2); + Result := True; +end; + +function DNSRRGetMX(const RR: TRRNameData; const pl: TPayLoadTCP; out + MX: TDNSRR_MX): Boolean; +var + idx: Integer; +begin + Result := False; + MX.preference := 0; + MX.exchange := ''; + if RR.RRMeta.Atype <> DNSQRY_MX then exit; + idx := RR.RDataSt; + if idx + SizeOf(Word) >= Length(pl) then exit; + Move(pl[idx],MX.preference, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + MX.exchange := stringfromlabel(pl, idx); + MX.preference := NToHs(MX.preference); + Result := True; +end; + +function DNSRRGetMX(const RR: TRRNameData; const pl: TPayLoad; out MX: TDNSRR_MX + ): Boolean; +var + idx: Integer; +begin + Result := False; + MX.preference := 0; + MX.exchange := ''; + if RR.RRMeta.Atype <> DNSQRY_MX then exit; + idx := RR.RDataSt; + if idx + SizeOf(Word) >= Length(pl) then exit; + Move(pl[idx],MX.preference, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + MX.exchange := stringfromlabel(pl, idx); + MX.preference := NToHs(MX.preference); + Result := True; +end; + +function DNSRRGetPTR(const RR: TRRNameData; const pl: TPayLoadTCP; out + ptr: TDNSDomainName): Boolean; +var + n: Integer; +begin + Result := False; + ptr := ''; + if RR.RRMeta.Atype <> DNSQRY_PTR then exit; + n := RR.RDataSt; + if (n + RR.RRMeta.RDLength) > Length(pl) then exit; + ptr := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetPTR(const RR: TRRNameData; const pl: TPayLoad; out + ptr: TDNSDomainName): Boolean; +var + n: Integer; +begin + Result := False; + ptr := ''; + if RR.RRMeta.Atype <> DNSQRY_PTR then exit; + n := RR.RDataSt; + if (n + RR.RRMeta.RDLength) > Length(pl) then exit; + ptr := stringfromlabel(pl, n); + Result := True; +end; + +function DNSRRGetSRV(const RR: TRRNameData; const pl: TPayload; out + srv: TDNSRR_SRV): Boolean; +var + idx: Integer; +begin + Result := False; + srv.priority := 0; + srv.weight := 0; + srv.port := 0; + srv.target := ''; + if RR.RRMeta.Atype <> DNSQRY_SRV then exit; + + idx := RR.RDataSt; + if idx + RR.RRMeta.RDLength > Length(pl) then exit; + + Move(pl[idx], srv.priority, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + Move(pl[idx], srv.weight, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + Move(pl[idx], srv.port, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + srv.target := stringfromlabel(pl, idx); + + srv.priority := NToHs(srv.priority); + srv.weight := NToHs(srv.weight); + srv.port := NToHs(srv.port); + + Result := True; +end; + +function DNSRRGetSRV(const RR: TRRNameData; const pl: TPayloadTCP; out + srv: TDNSRR_SRV): Boolean; +var + idx: Integer; +begin + Result := False; + srv.priority := 0; + srv.weight := 0; + srv.port := 0; + srv.target := ''; + if RR.RRMeta.Atype <> DNSQRY_SRV then exit; + + idx := RR.RDataSt; + if idx + RR.RRMeta.RDLength > Length(pl) then exit; + + Move(pl[idx], srv.priority, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + Move(pl[idx], srv.weight, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + Move(pl[idx], srv.port, SizeOf(Word)); + Inc(idx, SizeOf(Word)); + if (Length(pl) - idx) < 2 then exit; + + srv.target := stringfromlabel(pl, idx); + + srv.priority := NToHs(srv.priority); + srv.weight := NToHs(srv.weight); + srv.port := NToHs(srv.port); + + Result := True; +end; + Function SkipAnsQueries(Var Ans : TQueryData; L : Integer) : integer; Var @@ -817,10 +1546,10 @@ begin Result:=0; With Ans do begin - qdcount := htons(qdcount); + h.qdcount := htons(h.qdcount); i:=0; q:=0; - While (Q<qdcount) and (i<l) do + While (Q<h.qdcount) and (i<l) do begin If Payload[i]>63 then begin @@ -842,6 +1571,39 @@ begin end; end; +function SkipAnsQueries(var Ans: TQueryDataLengthTCP; L: Integer): integer; +var + Q,I : Integer; + +begin + Result:=0; + With Ans do + begin + h.qdcount := htons(h.qdcount); + i:=0; + q:=0; + While (Q<h.qdcount) and (i<l) do + begin + If Payload[i]>63 then + begin + Inc(I,6); + Inc(Q); + end + else + begin + If Payload[i]=0 then + begin + inc(q); + Inc(I,5); + end + else + Inc(I,Payload[i]+1); + end; + end; + Result:=I; + end; +end; + { --------------------------------------------------------------------- DNS Query functions. ---------------------------------------------------------------------} @@ -857,7 +1619,7 @@ Var begin Result:=False; - With Qry do + With Qry.h do begin ID[0]:=Random(256); ID[1]:=Random(256); @@ -890,39 +1652,256 @@ begin AL:=SizeOf(SA); L:=fprecvfrom(Sock,@ans,SizeOf(Ans),0,@SA,@AL); fpclose(Sock); - // Check lenght answer and fields in header data. - If (L<12) or not CheckAnswer(Qry,Ans) Then + + if L < 12 then exit; + // Return Payload length. + Anslen:=L-12; + // even though we may still return false to indicate an error, if AnsLen + // is >= 0 then the caller knows the dns server responded. + If not CheckAnswer(Qry.h,Ans.h) Then exit; - // Return Payload length. - Anslen:=L-12; - Result:=True; + Result:=True; + //end; end; -function stringfromlabel(pl: TPayLoad; start: integer): string; +function FetchDNSResponse(sock: Cint; out len: ssize_t; + out Ans: TQueryDataLengthTCP): TTCPSocketResult; var - l,i: integer; + respsize: Word; + L: ssize_t; + +begin + Result := srOK; + len := 0; + + // peek into the socket buffer and see if a full message is waiting. + L := fprecv(sock, @Ans, SizeOf(Ans), MSG_PEEK); + if L = 0 then + begin + Result := srSocketClose; + exit; + end; + // The first two bytes of a DNS TCP payload is the number of octets in the + // response, excluding the two bytes of length. This lets us see if we've + // received the full response. + respsize := NToHs(Ans.length); + if (L < 2) or (L < (respsize + SizeOf(Ans.length))) then + begin + Result := srPartial; + exit; + end; + + // The full DNS response is waiting in the buffer. Get it now. + len := fprecv(sock, @Ans, SizeOf(Ans), 0); +end; + +function QueryTCP(Resolver: Integer; var Qry: TQueryDataLength; + var Ans: TQueryDataLengthTCP; QryLen: Integer; var AnsLen: Integer): Boolean; +Var + SA : TInetSockAddr; + Sock : cint; + L: ssize_t; + RTO : Longint; + ReadFDS : TFDSet; + count: Integer; + sendsize: ssize_t; + respsize: Word; + resp: TTCPSocketResult; + tstart: QWord; + +begin + tstart := GetTickCount64; + Result:=False; + With Qry.hpl.h do + begin + ID[0]:=Random(256); + ID[1]:=Random(256); + Flags1:=QF_RD; + Flags2:=0; + qdcount:=htons(1); // was 1 shl 8; + ancount:=0; + nscount:=0; + arcount:=0; + end; + Sock:=FpSocket(AF_INET,SOCK_STREAM,0); + If Sock=-1 then + exit; + With SA do + begin + sin_family:=AF_INET; + sin_port:=htons(DNSport); + sin_addr.s_addr:=cardinal(DNSServers[Resolver]); // octets already in net order + end; + + // connect to the resolver + if (fpconnect(Sock, @SA, SizeOf(SA)) <> 0) then + exit; + + // send the query to the resolver + sendsize := QryLen + SizeOf(Qry.hpl.h) + SizeOf(Qry.length); + count := fpsend(Sock,@Qry,sendsize,0); + if count < sendsize then + begin + fpclose(Sock); + exit; + end; + + // tell other side we're done writing. + fpshutdown(Sock, SHUT_WR); + + RTO := 5000; + fpFD_ZERO(ReadFDS); + fpFD_Set(sock,ReadFDS); + + // select to wait for data + if fpSelect(sock+1, @ReadFDS, Nil, Nil, RTO)<=0 then + begin + // timed out, nothing received. + fpclose(sock); + exit; + end; + + // for partial responses, keep trying until all data received or the + // timeout period has elapsed. the timeout period includes the time + // spent waiting on select. + resp := FetchDNSResponse(Sock, L, Ans); + while (resp = srPartial) and ((GetTickCount64 - tstart) < RTO) do + begin + // need to sleep to avoid high cpu. 50ms means a 5 second timeout will + // make up to 100 calls to FetchDNSResponse. + Sleep(50); + resp := FetchDNSResponse(Sock, L, Ans); + end; + + fpclose(sock); + if resp <> srOK then exit; + + // Set AnsLen to be the size of the payload minus the header. + Anslen := L-SizeOf(Qry.hpl.h); + // if the final check finds problems with the answer, we'll return false + // but AnsLen being >=0 will let the caller know that the server did + // respond, but either declined to answer or couldn't. + If not CheckAnswer(Qry.hpl.h,Ans.h) then + exit; + Result:=True; +end; + +{ +Read a string from the payload buffer. Handles compressed as well as +regular labels. On termination start points to the character after the +end of the str. +} + +function stringfromlabel(pl: TPayLoad; var start: Integer): string; +var + l,i,n,lc: integer; + ptr: Word; + ptrseen: Boolean = False; begin result := ''; l := 0; i := 0; + n := start; + // Label counter. Per rfc1035, s. 3.1, each label is at least 2 bytes and the + // max length for a domain is 255, so there can't be more than 127 labels. + // This helps to short-circuit loops in label pointers. + lc := 0; repeat - l := ord(pl[start]); + // each iteration of this loop is for one label. whether a pointer or a + // regular label, we need 2 bytes headroom minimum. + if n > (Length(pl) - 2) then break; + l := ord(pl[n]); { compressed reply } while (l >= 192) do begin - { the -12 is because of the reply header length } - start := (l and not(192)) shl 8 + ord(pl[start+1]) - 12; - l := ord(pl[start]); + if not ptrseen then start := n + 2; + ptrseen := True; + ptr := (l and not(192)) shl 8 + ord(pl[n+1]); + {ptr must point backward and be >= 12 (for the dns header.} + if (ptr >= (n+12)) or (ptr < 12) then l := 0 // l=0 causes loop to exit + else + begin + { the -12 is because of the reply header length. we do the decrement + here to avoid overflowing if ptr < 12.} + n := ptr - 12; + l := ord(pl[n]); + end; + end; + // check we point inside the buffer + if (n+l+1) > Length(pl) then l := 0; + if l <> 0 then begin + setlength(result,length(result)+l); + move(pl[n+1],result[i+1],l); + result := result + '.'; + inc(n,l); inc(n); + inc(i,l); inc(i); + if n > start then start := n; + end; + Inc(lc); // label count + until (l = 0) or (lc > 127); + // per rfc1035, section 4.1.4, a domain name may be represented by + // either a sequence of labels followed by 0, or a pointer, or a series + // of labels followed by a pointer. If there's a pointer there's no 0 to + // skip over when calculating the final index. + if not ptrseen then Inc(start); // jump past the 0. + if (Length(result) > 0) and (result[length(result)] = '.') then + setlength(result,length(result)-1); +end; + +function stringfromlabel(pl: TPayLoadTCP; var start: Integer): string; +var + l,i,n,lc: integer; + ptr: Word; + ptrseen: Boolean = False; +begin + result := ''; + l := 0; + i := 0; + n := start; + // Label counter. Per rfc1035, s. 3.1, each label is at least 2 bytes and the + // max length for a domain is 255, so there can't be more than 127 labels. + // This helps to short-circuit loops in label pointers. + lc := 0; + repeat + // each iteration of this loop is for one label. whether a pointer or a + // regular label, we need 2 bytes headroom minimum. + if n > (Length(pl) - 2) then break; + l := ord(pl[n]); + { compressed reply } + while (l >= 192) do + begin + if not ptrseen then start := n + 2; + ptrseen := True; + ptr := (l and not(192)) shl 8 + ord(pl[n+1]); + {ptr must point backward and be >= 12 (for the dns header.} + if (ptr >= (n+12)) or (ptr < 12) then l := 0 // l=0 causes loop to exit + else + begin + { the -12 is because of the reply header length. we do the decrement + here to avoid overflowing if ptr < 12.} + n := ptr - 12; + l := ord(pl[n]); + end; end; + // check we point inside the buffer + if (n+l+1) > Length(pl) then l := 0; if l <> 0 then begin setlength(result,length(result)+l); - move(pl[start+1],result[i+1],l); + move(pl[n+1],result[i+1],l); result := result + '.'; - inc(start,l); inc(start); + inc(n,l); inc(n); inc(i,l); inc(i); + if n > start then start := n; end; - until l = 0; - if result[length(result)] = '.' then setlength(result,length(result)-1); + Inc(lc); // label count + until (l = 0) or (lc > 127); + // per rfc1035, section 4.1.4, a domain name may be represented by + // either a sequence of labels followed by 0, or a pointer, or a series + // of labels followed by a pointer. If there's a pointer there's no 0 to + // skip over when calculating the final index. + if not ptrseen then Inc(start); // jump past the 0. + if (Length(result) > 0) and (result[length(result)] = '.') then + setlength(result,length(result)-1); end; Function ResolveNameAt(Resolver : Integer; HostName : String; Var Addresses : Array of THostAddr; Recurse: Integer) : Integer; @@ -941,7 +1920,7 @@ begin else begin AnsStart:=SkipAnsQueries(Ans,AnsLen); - MaxAnswer:=Ans.AnCount-1; + MaxAnswer:=Ans.h.AnCount-1; If MaxAnswer>High(Addresses) then MaxAnswer:=High(Addresses); I:=0; @@ -1022,7 +2001,7 @@ begin end else begin AnsStart:=SkipAnsQueries(Ans,AnsLen); - MaxAnswer:=Ans.AnCount-1; + MaxAnswer:=Ans.h.AnCount-1; If MaxAnswer>High(Addresses) then MaxAnswer:=High(Addresses); I:=0; @@ -1085,7 +2064,7 @@ begin else begin AnsStart:=SkipAnsQueries(Ans,AnsLen); - MaxAnswer:=Ans.AnCount-1; + MaxAnswer:=Ans.h.AnCount-1; If MaxAnswer>High(Names) then MaxAnswer:=High(Names); I:=0; diff --git a/avx512-0037785/packages/fcl-net/tests/netdbtest.pp b/avx512-0037785/packages/fcl-net/tests/netdbtest.pp new file mode 100644 index 0000000000..4a70bc76fa --- /dev/null +++ b/avx512-0037785/packages/fcl-net/tests/netdbtest.pp @@ -0,0 +1,4615 @@ +unit netdbtest; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, testregistry, Sockets, math, netdb; + +const + FAKETLD = 'doesnotexist'; + FAKEDOMAIN = 'fakedomain'; + + FAKEFQDN=FAKEDOMAIN+'.'+FAKETLD; + +type + TDomainCompressionOffset = packed record + nm: String; + offset: Word; + end; + TDomainCompressionTable = Array of TDomainCompressionOffset; + + TTwoByteArr = array[0 .. 1] of Byte; + TDNSDomainPointer = packed record + case b: boolean of + true: (ba: TTwoByteArr); + false: (b1,b2: Byte); + end; + + TDNSDomainByteStream = packed record + ulabels: Array of byte; + cptr: Word; + end; + + TBuffer = Array of Byte; + + // can't use dynamic arrays in variant records, so fudge things by + // having between 1 and 5 subsstrings per text RR. it's good enough + // for these tests. + TTextArray = array [1 .. 5] of ShortString; + + TFakeQuery = record + nm: ShortString; + qtype, qclass: Word; + end; + + TFakeSOA = record + mn,rn: ShortString; + serial,refresh,retry,expire,min: Cardinal; + end; + TFakeMX = record + pref: Word; + exch: ShortString; + end; + TFakeSRV = record + priority, weight, port: Word; + target: ShortString; + end; + + TFakeRR = record + RRName : ShortString; + AClass : Word; + TTL : Cardinal; + RDLength : Word; + case Atype: Word of + DNSQRY_A: (ip: THostAddr); + DNSQRY_AAAA: (ip6: THostAddr6); + DNSQRY_CNAME: (cn: ShortString); + DNSQRY_MX: (fmx: TFakeMX); + DNSQRY_NS: (nsh: ShortString); + DNSQRY_PTR: (ptr: ShortString); + DNSQRY_SOA: (fsoa: TFakeSoa); + DNSQRY_TXT: (sstrcount: Byte; txtarr: TTextArray); + DNSQRY_SRV: (fsrv: TFakeSRV); + end; + + TRRSection = Array of TFakeRR; + + TFakeDNSResponse = record + strtable: TDomainCompressionTable; + compresslabels: Boolean; + hdr: TDNSHeader; + qry: TFakeQuery; + answers, authority, additional: TRRSection; + end; + + TRDataWriteRes = packed record + bw, etw: Word; + end; + + { TNetDbTest } + + TNetDbTest= class(TTestCase) + strict private + tsl: TStringList; + protected + procedure SetUp; override; + procedure TearDown; override; + + procedure BuildFakeRR_A(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); + procedure BuildFakeRR_AAAA(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); + procedure BuildFakeRR_MX(out RR: TFakeRR; nm: String; ttl: Cardinal; + pref: Word; exch: ShortString ); + procedure BuildFakeRR_NS(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); + procedure BuildFakeRR_PTR(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); + procedure BuildFakeRR_CNAME(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); + procedure BuildFakeRR_SOA(out RR: TFakeRR; nm: String; ttl: Cardinal; + mn,rn: ShortString; serial,refresh,retry,expire,min: Cardinal); + procedure BuildFakeRR_TXT(out RR: TFakeRR; nm: String; ttl: Cardinal; + n: Byte; txt: TTextArray); + procedure BuildFakeRR_SRV(out RR: TFakeRR; nm: String; ttl: Cardinal; + priority, weight, port: Word; target: ShortString); + + procedure CopyBytesTo(var buf: TPayLoad; startidx,destidx,count: Word); + procedure CopyBytesTo(var buf: TPayLoadTCP; startidx,destidx,count: Word); + + function WriteNumToBuffer(var buf: TBuffer; var offset: Cardinal; + val: Word): Word; + function WriteNumToBuffer(var buf: TBuffer; var offset: Cardinal; + val: Cardinal): Word; + + function WriteNumToBufferN(var buf: TBuffer; var offset: Cardinal; + val: Word): Word; + function WriteNumToBufferN(var buf: TBuffer; var offset: Cardinal; + val: Cardinal): Word; + + function WriteMXAsRData(var buf: TBuffer; var offset: Cardinal; + fmx: TFakeMX): TRDataWriteRes; + function WriteSOAasRData(var buf: TBuffer; var offset: Cardinal; + fsoa: TFakeSOA): TRDataWriteRes; + function WriteSOAasRData(var buf: TBuffer; var offset: Cardinal; + fsoa: TFakeSOA; var ctbl: TDomainCompressionTable): TRDataWriteRes; + function WriteAAAAasRData(var buf: TBuffer; var offset: Cardinal; + ip6: THostAddr6): TRDataWriteRes; + function WriteAasRData(var buf: TBuffer; var offset: Cardinal; + ip: THostAddr): TRDataWriteRes; + + function WriteSRVasRData(var buf: TBuffer; var offset: Cardinal; + fsrv: TFakeSRV): TRDataWriteRes; + function WriteSRVasRData(var buf: TBuffer; var offset: Cardinal; + fsrv: TFakeSRV; var ctbl: TDomainCompressionTable): TRDataWriteRes; + + function WriteMXAsRData(var buf: TBuffer; var offset: Cardinal; + fmx: TFakeMX; var ctbl: TDomainCompressionTable): TRDataWriteRes; + + function CalcRdLength(o: TDNSDomainByteStream): Word; + function CalcRdLength(o: TTextArray): Word; + function WriteTextRecAsRData(var buf: TBuffer; var offset: Cardinal; + tt: TTextArray): TRDataWriteRes; + + function DomainNameToByteStream(nm: ShortString; + var ctbl: TDomainCompressionTable): TDNSDomainByteStream; + function DomainNameToByteStream(nm: ShortString): TDNSDomainByteStream; + + function WriteDNSDomainByteStreamToBuffer(var buf: TBuffer; + var offset: Cardinal; dbs: TDNSDomainByteStream): Word; + + function WriteDomainAsRdata(var buf: TBuffer; var offset: Cardinal; + dbs: TDNSDomainByteStream): TRDataWriteRes; + + function WriteRRToBuffer(var buf: TBuffer; var offset: Cardinal; + rr: TFakeRR): Word; + function WriteRRToBuffer(var buf: TBuffer; var offset: Cardinal; + rr: TFakeRR; var ctbl: TDomainCompressionTable): Word; + function FakeDNSResponseToByteBuffer(fdr: TFakeDNSResponse; + out buf: TBuffer; compress: Boolean = False): Cardinal; + function BufferToPayload(const buf: TBuffer; out pl: TPayload): Boolean; + function BufferToPayload(const buf: TBuffer; out pl: TPayLoadTCP): Boolean; + + function BuildQueryData(fdr: TFakeDNSResponse; out qd: TQueryData; + out qlen: Word; Compress: Boolean = False): Boolean; + + function BuildQueryData(fdr: TFakeDNSResponse; + out qd: TQueryDataLengthTCP; out qlen: Word; + Compress: Boolean = False): Boolean; + + function BuildTruncatedQueryData(fdr: TFakeDNSResponse; out qd: TQueryData; + out qlen: Word; truncoffset: Word): Boolean; + + procedure BuildFakeResponseA(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseAAAA(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseMX(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseSOA(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseCNAME(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseNS(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponsePTR(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseTXT(nm: ShortString; out fr: TFakeDNSResponse); + procedure BuildFakeResponseSRV(nm: ShortString; out fr: TFakeDNSResponse); + + published + procedure TestBuildPayloadSimple; + procedure TestBuildPayloadSimpleEmpty; + procedure TestBuildPayloadSimpleEndDot; + procedure TestBuildPayloadSimpleStartDot; + procedure TestBuildPayloadSimpleMultipleDot; + + { * straightforward tests for the api with valid data. Have to test each + * known RR type with both TCP and UDP buffer functions, and with and + * without compression of domain names. + * No network calls will be made. These tests hit all functions for + * processing dns requests except network functions.} + procedure TestDnsQueryUDP_A; + procedure TestDnsQueryTCP_A; + procedure TestDnsQueryCompressUDP_A; + procedure TestDnsQueryCompressTCP_A; + + procedure TestDnsQueryUDP_AAAA; + procedure TestDnsQueryTCP_AAAA; + procedure TestDnsQueryCompressUDP_AAAA; + procedure TestDnsQueryCompressTCP_AAAA; + + procedure TestDnsQueryUDP_MX; + procedure TestDnsQueryTCP_MX; + procedure TestDnsQueryCompressUDP_MX; + procedure TestDnsQueryCompressTCP_MX; + + procedure TestDnsQueryUDP_SOA; + procedure TestDnsQueryTCP_SOA; + procedure TestDnsQueryCompressUDP_SOA; + procedure TestDnsQueryCompressTCP_SOA; + + procedure TestDnsQueryUDP_CNAME; + procedure TestDnsQueryTCP_CNAME; + procedure TestDnsQueryCompressUDP_CNAME; + procedure TestDnsQueryCompressTCP_CNAME; + + procedure TestDnsQueryUDP_NS; + procedure TestDnsQueryTCP_NS; + procedure TestDnsQueryCompressUDP_NS; + procedure TestDnsQueryCompressTCP_NS; + + procedure TestDnsQueryUDP_PTR; + procedure TestDnsQueryTCP_PTR; + procedure TestDnsQueryCompressUDP_PTR; + procedure TestDnsQueryCompressTCP_PTR; + + procedure TestDnsQueryUDP_TXT; + procedure TestDnsQueryTCP_TXT; + procedure TestDnsQueryCompressUDP_TXT; + procedure TestDnsQueryCompressTCP_TXT; + + procedure TestDnsQueryUDP_SRV; + procedure TestDnsQueryTCP_SRV; + procedure TestDnsQueryCompressUDP_SRV; + procedure TestDnsQueryCompressTCP_SRV; + + { + * Tests with invalid input data. These attempt to simulate a hostile + * dns server returning deliberately invalid data in an attempt to + * cause a buffer overflow, memory corruption, or DDOS. + } + + // buffer truncated so RRs have invalid types. + procedure TestDnsQueryTruncateRR_UDP_A; + + { + * Tests of DNSRRGet* functions where RR is near the end of the buffer, + * testing both when the RR just fits, and when it doesn't. + } + procedure TestDnsRRBufferEdgeA; + procedure TestDnsRRBufferPastEdgeA; + procedure TestDnsRRBufferEdgeAAAA; + procedure TestDNsRRBufferPastEdgeAAAA; + procedure TestDnsRRBufferEdgeMX; + procedure TestDnsRRBufferPastEdgeMX; + procedure TestDnsRRBufferEdgeSOA; + procedure TestDnsRRBufferPastEdgeSOA; + procedure TestDnsRRBufferEdgeSRV; + procedure TestDnsRRBufferPastEdgeSRV; + procedure TestDnsRRBufferEdgeCNAME; + procedure TestDnsRRBufferPastEdgeCNAME; + procedure TestDnsRRBufferEdgeNS; + procedure TestDnsRRBufferPastEdgeNS; + procedure TestDnsRRBufferEdgePTR; + procedure TestDnsRRBufferPastEdgePTR; + procedure TestDnsRRBufferEdgeTXT; + procedure TestDnsRRBufferPastEdgeTXT; + + + { + * the TCP variants. identical code, but qd variable is a different type + * and so different paths get followed in netdb. + } + procedure TestDnsRRBufferEdgeTCPA; + procedure TestDnsRRBufferPastEdgeTCPA; + procedure TestDnsRRBufferEdgeTCPAAAA; + procedure TestDNsRRBufferPastEdgeTCPAAAA; + procedure TestDnsRRBufferEdgeTCPMX; + procedure TestDnsRRBufferPastEdgeTCPMX; + procedure TestDnsRRBufferEdgeTCPSOA; + procedure TestDnsRRBufferPastEdgeTCPSOA; + procedure TestDnsRRBufferEdgeTCPSRV; + procedure TestDnsRRBufferPastEdgeTCPSRV; + procedure TestDnsRRBufferEdgeTCPCNAME; + procedure TestDnsRRBufferPastEdgeTCPCNAME; + procedure TestDnsRRBufferEdgeTCPNS; + procedure TestDnsRRBufferPastEdgeTCPNS; + procedure TestDnsRRBufferEdgeTCPPTR; + procedure TestDnsRRBufferPastEdgeTCPPTR; + procedure TestDnsRRBufferEdgeTCPTXT; + procedure TestDnsRRBufferPastEdgeTCPTXT; + + // Testing of NextNameRR at buffer edge and beyond. this differs from + // the above tests in that they tests DNSGet* at the edge, but NextNameRR + // is never called to read at the edge in those functions. + // Because NextNameRR does nothing that is specific to RR types it's + // not necessary to test with each type of RR. + + procedure TestNextNameRREdgeA; + procedure TestNextNameRRPastEdgeA; + procedure TestNextNameRREdgeTCPA; + procedure TestNextNameRRPastEdgeTCPA; + + { + * Test GetRRrecords at and beyond buffer boundaries. + } + procedure TestGetRRrecordsInvalidStart; + procedure TestGetRRrecordsInvalidStartTCP; + + { + Tests for GetFixlenStr + } + procedure TestGetFixLenStrSimple; + procedure TestGetFixLenStrSimpleTCP; + procedure TestGetFixLenStrSimpleAtEdge; + procedure TestGetFixLenStrSimpleTCPAtEdge; + procedure TestGetFixLenStrSimplePastEdge; + procedure TestGetFixLenStrSimpleTCPPastEdge; + + + { + * Test stringfromlabel with buffer edges and beyond. Its behaviour + * at present is to drop any label that would exceed the buffer boundary + * but still return any other labels successfully received. + + * Some of the previous tests already verify what happens with a label + * that occurs on the edge. See the tests for TestDnsRRBufferEdgeSRV + * and TestDnsRRBufferEdgeTCPSRV, TestDnsRRBufferEdgeCNAME, etc. + } + + // read a label starting at the end of the buffer where the count is + // greater than 0. + procedure TestStringFromLabelCountAsLastByte; + procedure TestStringFromLabelCountAsLastByteTCP; + + // compressed label + procedure TestStringFromLabelCompress; + procedure TestStringFromLabelCompressTCP; + // another compressed label test, this time with one uncompressed label + procedure TestStringFromLabelCompressWithUncompressedLabel; + // as above, but on the tcp payload buffer + procedure TestStringFromLabelCompressWithUncompressedLabelTCP; + // compressed label at the edge of the buffer + procedure TestStringFromLabelCompressEndBuffer; + // compressed label at the edge of the tcp buffer + procedure TestStringFromLabelCompressEndBufferTCP; + // test stringfromlabel when last byte is 192. 192 is the signal + // that the next byte is a pointer offset, but of course there's + // no next byte. + procedure TestStringFromLabelCompressSplit; + // repeat using TCP buffer variant + procedure TestStringFromLabelCompressSplitTCP; + // test that stringfromlabel rejects pointers that go forward. per + // rfc 1035, pointers must go backward. + procedure TestStringFromLabelCompressPtrFwd; + procedure TestStringFromLabelCompressPtrFwdTCP; + // fill buffer with 192, pointer marker, then try stringfromlabel on it. + procedure TestStringFromLabelCompressAllPtrStart; + procedure TestStringFromLabelCompressAllPtrStartTCP; + + // test string from label where second byte is 0. + procedure TestStringFromLabelCompressedZero; + procedure TestStringFromLabelCompressedZeroTCP; + + // test whether an infinite loop can be triggered. + procedure TestStringFromLabelInfiniteLoop; + procedure TestStringFromLabelInfiniteLoopTCP; + + // test short domain less than 12 chars. this tests that dns pointer + // calculations in stringfromlabel are correct + procedure TestCompressShortDomain; + procedure TestCompressShortDomainTCP; + end; + +implementation + +procedure dump_payload(const pl: TBuffer); +var + idx,llen: Cardinal; +begin + idx := 0; + llen := 0; + for idx := 0 to Length(pl) - 1 do + begin + write('['+inttostr(idx)+'] '+IntToHex(pl[idx],2)); + if (pl[idx] > 48) and (pl[idx] < 123) then + write(' ' + chr(pl[idx])) + else + write(' .'); + write(' '); + Inc(llen); + if llen >= 6 then + begin + llen := 0; + writeln(); + end; + end; + if llen > 0 then + begin + writeln(); + end; +end; + +procedure dump_payload(const pl: TPayload; count: Word); +var + idx,llen: Cardinal; +begin + idx := 0; + llen := 0; + for idx := 0 to count - 1 do + begin + write('['+inttostr(idx)+'] '+IntToHex(pl[idx],2)); + if (pl[idx] > 48) and (pl[idx] < 123) then + write(' ' + chr(pl[idx])) + else + write(' .'); + write(' '); + Inc(llen); + if llen >= 6 then + begin + llen := 0; + writeln(); + end; + end; + if llen > 0 then + begin + writeln(); + end; +end; + +function LookupStr(ls: String; stt: TDomainCompressionTable; out idx: Word): Boolean; +var + so: TDomainCompressionOffset; +begin + Result := False; + for so in stt do + begin + if ls = so.nm then + begin + Result := True; + idx := so.offset; + exit; + end; + end; +end; + +function AddStr(ls: String; var stt: TDomainCompressionTable; idx: Word): Boolean; +var + so: TDomainCompressionOffset; +begin + so.nm := ls; + so.offset := idx; + SetLength(stt, Length(stt)+1); + stt[Length(stt)-1] := so; + Result := True; +end; + +function GetDnsDomainPointer(offset: Word): TDNSDomainPointer; +begin + Result.b1 := 0; + Result.b2 := 0; + // dns comp. ptr can't be > 2 ** 14 or 16383 + if offset > 16383 then exit; + Result.b1 := (offset SHR 8) OR 192; + Result.b2 := (offset AND $00FF); +end; + +procedure DomainNameToLabels(const dmn: String; var labels: TStringList); +begin + labels.Clear; + labels.Delimiter := '.'; + labels.StrictDelimiter := True; + labels.DelimitedText := dmn; +end; + +procedure TNetDbTest.BuildFakeRR_A(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_A; + RR.AClass := 1; + RR.TTL := ttl; + RR.ip := StrToNetAddr(val); + RR.RDLength := 4; +end; + +procedure TNetDbTest.BuildFakeRR_AAAA(out RR: TFakeRR; nm: String; + ttl: Cardinal; val: String); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_AAAA; + RR.AClass := 1; + RR.TTL := ttl; + RR.ip6 := StrToNetAddr6(val); + RR.RDLength := 16; +end; + +procedure TNetDbTest.BuildFakeRR_MX(out RR: TFakeRR; nm: String; ttl: Cardinal; + pref: Word; exch: ShortString ); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_MX; + RR.AClass := 1; + RR.TTL := ttl; + RR.fmx.pref := pref; + RR.fmx.exch := exch; +end; + +procedure TNetDbTest.BuildFakeRR_NS(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_NS; + RR.AClass := 1; + RR.TTL := ttl; + RR.nsh := val; +end; + +procedure TNetDbTest.BuildFakeRR_PTR(out RR: TFakeRR; nm: String; ttl: Cardinal; + val: String); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_PTR; + RR.AClass := 1; + RR.TTL := ttl; + RR.ptr := val; +end; + +procedure TNetDbTest.BuildFakeRR_CNAME(out RR: TFakeRR; nm: String; + ttl: Cardinal; val: String); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_CNAME; + RR.AClass := 1; + RR.TTL := ttl; + RR.cn := val; +end; + +procedure TNetDbTest.BuildFakeRR_SOA(out RR: TFakeRR; nm: String; ttl: Cardinal; + mn,rn: ShortString; serial,refresh,retry,expire,min: Cardinal); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_SOA; + RR.AClass := 1; + RR.TTL := ttl; + RR.fsoa.mn := mn; + RR.fsoa.rn := rn; + RR.fsoa.serial := serial; + RR.fsoa.refresh := refresh; + RR.fsoa.retry := retry; + RR.fsoa.expire := expire; + RR.fsoa.min := min; +end; + +procedure TNetDbTest.BuildFakeRR_TXT(out RR: TFakeRR; nm: String; ttl: Cardinal; + n: Byte; txt: TTextArray); +var + idx: Byte; +begin + RR.RRName := nm; + RR.Atype := DNSQRY_TXT; + RR.AClass := 1; + RR.TTL := ttl; + RR.sstrcount := n; + RR.txtarr[1] := ''; + RR.txtarr[2] := ''; + RR.txtarr[3] := ''; + RR.txtarr[4] := ''; + RR.txtarr[5] := ''; + for idx := Low(txt) to Min(n, High(txt)) do + RR.txtarr[idx] := txt[idx]; +end; + +procedure TNetDbTest.BuildFakeRR_SRV(out RR: TFakeRR; nm: String; ttl: Cardinal; + priority, weight, port: Word; target: ShortString); +begin + RR.RRName := nm; + RR.Atype := DNSQRY_SRV; + RR.AClass := 1; + RR.TTL := ttl; + RR.fsrv.priority := priority; + RR.fsrv.weight := weight; + RR.fsrv.port := port; + RR.fsrv.target := target; +end; + +function TNetDbTest.CalcRdLength(o: TTextArray): Word; +var + tmps: ShortString; +begin + Result := 0; + for tmps in o do + begin + if tmps = '' then break; + Result := Result + Length(tmps)+1; // don't forget length byte! + end; +end; + +function TNetDbTest.WriteAasRData(var buf: TBuffer; var offset: Cardinal; + ip: THostAddr): TRDataWriteRes; +var + s,l: Word; +begin + s := offset; + l := SizeOf(ip.s_addr); + Result.etw := l + 2; //rdlength +2 for length itself + // rdlength + WriteNumToBuffer(buf, offset, l); + // rr data + WriteNumToBufferN(buf, offset, ip.s_addr); + Result.bw := offset - s; +end; + +function TNetDbTest.WriteSRVasRData(var buf: TBuffer; var offset: Cardinal; + fsrv: TFakeSRV): TRDataWriteRes; +var + s, l: Word; + dmbs: TDNSDomainByteStream; +begin + s := offset; + dmbs := DomainNameToByteStream(fsrv.target); + l := CalcRdLength(dmbs) + SizeOf(Word) * 3; + Result.etw := l + 2; //rdlength +2 for length byte + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // RR data + WriteNumToBuffer(buf, offset, fsrv.priority); + WriteNumToBuffer(buf, offset, fsrv.weight); + WriteNumToBuffer(buf, offset, fsrv.port); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + Result.bw := offset - s; +end; + +function TNetDbTest.WriteSRVasRData(var buf: TBuffer; var offset: Cardinal; + fsrv: TFakeSRV; var ctbl: TDomainCompressionTable): TRDataWriteRes; +var + s, l: Word; + dmbs: TDNSDomainByteStream; +begin + s := offset; + dmbs := DomainNameToByteStream(fsrv.target, ctbl); + l := CalcRdLength(dmbs) + SizeOf(Word) * 3; + Result.etw := l + 2; //rdlength +2 for length byte + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // RR data + WriteNumToBuffer(buf, offset, fsrv.priority); + WriteNumToBuffer(buf, offset, fsrv.weight); + WriteNumToBuffer(buf, offset, fsrv.port); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + Result.bw := offset - s; +end; + +function TNetDbTest.WriteMXAsRData(var buf: TBuffer; var offset: Cardinal; + fmx: TFakeMX; var ctbl: TDomainCompressionTable): TRDataWriteRes; +var + s, l: Word; + dmbs: TDNSDomainByteStream; +begin + s := offset; + dmbs := DomainNameToByteStream(fmx.exch, ctbl); + l := SizeOf(fmx.pref) + CalcRdLength(dmbs); + Result.etw := l + 2; // we'll write rdlength bytes+2 bytes for length itself. + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // RR data + // pref + WriteNumToBuffer(buf, offset, fmx.pref); + // exchange + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + Result.bw := offset - s; +end; + +function TNetDbTest.CalcRdLength(o: TDNSDomainByteStream): Word; +begin + Result := Length(o.ulabels); + if o.cptr > 0 then Inc(Result,2); +end; + +function TNetDbTest.WriteAAAAasRData(var buf: TBuffer; var offset: Cardinal; + ip6: THostAddr6): TRDataWriteRes; +var + s,l: Word; +begin + s := offset; + l := SizeOf(ip6.u6_addr32); + Result.etw := l + 2; //rdlength + 2 for length itself + // rdlength + WriteNumToBuffer(buf, offset, l); + // rr data + Move(ip6.s6_addr, buf[offset], l); + Inc(offset, l); + Result.bw := offset - s; +end; + +function TNetDbTest.WriteSOAasRData(var buf: TBuffer; var offset: Cardinal; + fsoa: TFakeSOA): TRDataWriteRes; +var + s, l: Word; + dmbsmn, dmbsrn: TDNSDomainByteStream; +begin + s := offset; + dmbsmn := DomainNameToByteStream(fsoa.mn); + dmbsrn := DomainNameToByteStream(fsoa.rn); + l := CalcRdLength(dmbsmn) + CalcRdLength(dmbsrn) + (SizeOf(Cardinal) * 5); + + Result.etw := l + 2; // rdlength bytes + 2 for length itself + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // rr data + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbsmn); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbsrn); + + WriteNumToBuffer(buf, offset, fsoa.serial); + WriteNumToBuffer(buf, offset, fsoa.refresh); + WriteNumToBuffer(buf, offset, fsoa.retry); + WriteNumToBuffer(buf, offset, fsoa.expire); + WriteNumToBuffer(buf, offset, fsoa.min); + + Result.bw := offset - s; +end; + +function TNetDbTest.WriteSOAasRData(var buf: TBuffer; var offset: Cardinal; + fsoa: TFakeSOA; var ctbl: TDomainCompressionTable): TRDataWriteRes; +var + s, l: Word; + dmbsmn, dmbsrn: TDNSDomainByteStream; +begin + s := offset; + dmbsmn := DomainNameToByteStream(fsoa.mn, ctbl); + dmbsrn := DomainNameToByteStream(fsoa.rn, ctbl); + l := CalcRdLength(dmbsmn) + CalcRdLength(dmbsrn) + (SizeOf(Cardinal) * 5); + Result.etw := l + 2; // rdlength bytes + 2 for length itself + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // rr data + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbsmn); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbsrn); + + WriteNumToBuffer(buf, offset, fsoa.serial); + WriteNumToBuffer(buf, offset, fsoa.refresh); + WriteNumToBuffer(buf, offset, fsoa.retry); + WriteNumToBuffer(buf, offset, fsoa.expire); + WriteNumToBuffer(buf, offset, fsoa.min); + + Result.bw := offset - s; +end; + +function TNetDbTest.WriteMXAsRData(var buf: TBuffer; var offset: Cardinal; + fmx: TFakeMX): TRDataWriteRes; +var + s, l: Word; + dmbs: TDNSDomainByteStream; +begin + Result.bw := 0; + s := offset; + dmbs := DomainNameToByteStream(fmx.exch); + l := SizeOf(fmx.pref) + CalcRdLength(dmbs); + Result.etw := l + 2; // we'll write rdlength + 2 bytes for the length itself. + + // rdlength + WriteNumToBuffer(buf, offset, l); + + // RR data + // pref + WriteNumToBuffer(buf, offset, fmx.pref); + // exchange + dmbs := DomainNameToByteStream(fmx.exch); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + Result.bw := offset - s; +end; + +function TNetDbTest.WriteTextRecAsRData(var buf: TBuffer; var offset: Cardinal; + tt: TTextArray): TRDataWriteRes; +var + s, l: Word; + ws: ShortString; +begin + s := offset; + l := CalcRdLength(tt); + Result.etw := l + 2; // rdlength +2 for length itself + // rdlength + WriteNumToBuffer(buf, offset, l); + + for ws in tt do + begin + if ws = '' then break; + Move(ws, buf[offset], Length(ws)+1); + Inc(offset,Length(ws)+1); + end; + + Result.bw := offset - s; +end; + +{ +Convert a domain name into a byte stream. Compression is supported using the +supplied compression table. +} +function TNetDbTest.DomainNameToByteStream(nm: ShortString; + var ctbl: TDomainCompressionTable): TDNSDomainByteStream; +var + dmn: ShortString; + offset,cmpoffset: Word; + ptrseen: Boolean = False; +begin + SetLength(Result.ulabels, 0); + Result.cptr := 0; + offset := 0; + + if nm = '' then exit; + DomainNameToLabels(nm, tsl); + if tsl.Count = 0 then exit; + + dmn := ''; + cmpoffset := 0; + + { + for a domain a.b.c, using the lookup table, + -> lookup (a.b.c), if not found, add to table, + -> lookup (b.c), if not found, add to table, + -> lookup (c), if not found, add to table, + + buf if any label domain is found, add the pointer to the buffer and stop. + } + repeat + dmn := tsl.DelimitedText; + ptrseen := LookupStr(dmn, ctbl, cmpoffset); + if ptrseen then + begin + // found the domain name. add a pointer, then we're done. Per RFC1035, + // section 4.1.4, a domain name is either a series of labels, a pointer, + // or a series of labels ending with a pointer. There's just one pointer + // for a domain name. + Result.cptr := cmpoffset; + break; + end + else + begin + // add the last full domain we looked up, not the working label, + // to the compression lookup table. E.g, add a.b.c rather than a. + // Add 12 for the dns header, which our buffer doesn't include, but + // api methods like stringfromlabel adjust offsets to account for it. + if Length(dmn) > 0 then AddStr(dmn, ctbl, offset+12); + // write the label to the buffer + dmn := tsl[0]; + tsl.Delete(0); + SetLength(Result.ulabels, (Length(Result.ulabels) + Length(dmn)+1)); + Result.ulabels[offset] := Length(dmn); + Inc(offset); + Move(dmn[1], Result.ulabels[offset], Length(dmn)); + Inc(offset, Length(dmn)); + end; + until tsl.Count = 0; + + // if we didn't see a pointer then we have to write a 0. see rfc1035, s4.1.4. + if not ptrseen then + begin + SetLength(Result.ulabels, Length(Result.ulabels) + 1); + Result.ulabels[offset] := 0; + Inc(offset); + end; +end; + +{ +This version of DomainNameToByteStream doesn't compress. +} +function TNetDbTest.DomainNameToByteStream(nm: ShortString + ): TDNSDomainByteStream; +var + dmn: ShortString; + offset: Word; +begin + SetLength(Result.ulabels, 0); + Result.cptr := 0; + offset := 0; + + if nm = '' then exit; + DomainNameToLabels(nm, tsl); + if tsl.Count = 0 then exit; + + for dmn in tsl do + begin + SetLength(Result.ulabels, (Length(Result.ulabels) + Length(dmn)+1)); + Result.ulabels[offset] := Length(dmn); + Inc(offset); + Move(dmn[1], Result.ulabels[offset], Length(dmn)); + Inc(offset, Length(dmn)); + end; + + SetLength(Result.ulabels, Length(Result.ulabels) + 1); + Result.ulabels[offset] := 0; +end; + +function TNetDbTest.WriteDNSDomainByteStreamToBuffer(var buf: TBuffer; + var offset: Cardinal; dbs: TDNSDomainByteStream): Word; +var + p: TDNSDomainPointer; + so: Word; +begin + Result := 0; + // no label, no pointer, no write for you. + if (Length(dbs.ulabels) = 0) and (dbs.cptr = 0) then exit; + if (offset + CalcRdLength(dbs)) > Length(buf) then exit; + + so := offset; + // labels can be empty, in which case we're writing just a pointer. + if Length(dbs.ulabels) > 0 then + begin + Move(dbs.ulabels[0], buf[offset], Length(dbs.ulabels)); + Inc(offset, Length(dbs.ulabels)); + end; + if dbs.cptr > 0 then + begin + p := GetDnsDomainPointer(dbs.cptr); + Move(p.ba, buf[offset], Length(p.ba)); + Inc(offset, Min(Length(p.ba), (Length(buf) - offset))); + end; + Result := offset - so; +end; + +{ +Write a domain name as RDATA. This means an RDLength (Word) and the +domain labels. +} +function TNetDbTest.WriteDomainAsRdata(var buf: TBuffer; var offset: Cardinal; + dbs: TDNSDomainByteStream): TRDataWriteRes; +var + s,l: Word; +begin + l := CalcRdLength(dbs); + Result.etw := l + 2; + s := offset; + WriteNumToBuffer(buf, offset,l); + WriteDNSDomainByteStreamToBuffer(buf, offset, dbs); + Result.bw := offset - s; +end; + + +procedure TNetDbTest.BuildFakeResponseA(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 2; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_A; + + // now the answer RRs + SetLength(fr.answers,2); + BuildFakeRR_A(fr.answers[0], nm, 300, '127.0.0.1'); + BuildFakeRR_A(fr.answers[1], nm, 215, '127.0.5.1'); +end; + +procedure TNetDbTest.BuildFakeResponseAAAA(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 2; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_AAAA; + + // now the answer RRs + SetLength(fr.answers,2); + BuildFakeRR_AAAA(fr.answers[0], nm, 300, 'fe80::3b92:3429:ff16:a3e4'); + BuildFakeRR_AAAA(fr.answers[1], nm, 215, 'fe80::92e6:baff:fe44:ffbb'); +end; + +procedure TNetDbTest.BuildFakeResponseMX(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 2; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_MX; + + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_MX(fr.answers[0], nm, 0, 10, 'mailer.'+FAKEFQDN); + // now an additional rr with the A record for the above. + SetLength(fr.additional, 2); + BuildFakeRR_A(fr.additional[0], 'mailer.'+FAKEFQDN, 0, + '172.16.27.238'); + BuildFakeRR_AAAA(fr.additional[1], 'mailer.'+FAKEFQDN, 0, + 'fe80::3b92:3429:ff16:a3e4'); +end; + +procedure TNetDbTest.BuildFakeResponseSOA(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_SOA; + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_SOA(fr.answers[0],FAKEFQDN,33, + 'mn.'+FAKEFQDN,'rn.'+FAKEFQDN,76543210, + 123,456,789,60); +end; + +procedure TNetDbTest.BuildFakeResponseCNAME(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_CNAME; + + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_CNAME(fr.answers[0], nm, 300, 'fakecname.'+FAKEFQDN); +end; + +procedure TNetDbTest.BuildFakeResponseNS(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_NS; + + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_NS(fr.answers[0], nm, 300, 'fakens.'+FAKEFQDN); +end; + +procedure TNetDbTest.BuildFakeResponsePTR(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_PTR; + + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_PTR(fr.answers[0], nm, 300, 'fakeptrans.'+FAKEFQDN); +end; + +procedure TNetDbTest.BuildFakeResponseTXT(nm: ShortString; out + fr: TFakeDNSResponse); +var + txtarr: TTextArray; +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_TXT; + + txtarr[1] := 'v=spf1 mx a:lists.'+FAKEFQDN; + txtarr[2] := 'Always look on the bright side of life!'; + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_TXT(fr.answers[0], nm, 300, 2, txtarr); +end; + +procedure TNetDbTest.BuildFakeResponseSRV(nm: ShortString; out + fr: TFakeDNSResponse); +begin + // metadata + SetLength(fr.strtable, 0); + + // start by building a fake header. + fr.hdr.ID[0] := 12; + fr.hdr.ID[1] := 34; + fr.hdr.flags1 := QF_QR or QF_RD; + fr.hdr.flags2 := 0; + fr.hdr.qdcount := 1; + fr.hdr.ancount := 1; + fr.hdr.nscount := 0; + fr.hdr.arcount := 0; + + // Next is the query part + fr.qry.nm := nm; + fr.qry.qclass := 1; + fr.qry.qtype := DNSQRY_SRV; + // now the answer RRs + SetLength(fr.answers,1); + BuildFakeRR_SRV(fr.answers[0],FAKEFQDN,3300,22,44,2201,'_this._that._other'); +end; + +{ +Test that BuildPayload puts the right values into the payload buffer. +} +procedure TNetDbTest.TestBuildPayloadSimple; +var + Q: TQueryData; + R, I,J,el: Integer; + S: String; +begin + R := BuildPayLoad(Q, FAKEFQDN, DNSQRY_A, 1); + // this is the expected length. Essentially, for each label, len(label)+1, + // then 4 bytes for the qclass and qtype, and 1 more for a 0 byte. + // rather than hardwire the length we calculate it so that no matter + // what the fake domain the test passes. + el := (Length(FAKEDOMAIN)+1)+(Length(FAKETLD)+1)+5; + AssertEquals('Payload byte count wrong:', el, R); + I := 0; + J := 0; + S := stringfromlabel(Q.Payload,I); + AssertEquals('Wrong domain name returned:',FAKEFQDN, S); + Move(Q.Payload[I],J,SizeOf(Word)); + AssertEquals('Wrong query type', DNSQRY_A, NToHs(J)); + Inc(I,2); + Move(Q.Payload[I],J,SizeOf(Word)); + AssertEquals('Wrong class', 1, NToHs(J)); +end; + +{ +Test building a payload with an empty str. +} +procedure TNetDbTest.TestBuildPayloadSimpleEmpty; +var + Q: TQueryData; + R: Integer; +begin + R := BuildPayLoad(Q, '', DNSQRY_A, 1); + AssertEquals('Payload byte count wrong:',-1, R); +end; + +{ +Test BuildQuery with a label that ends in a dot. This should be allowed. +A dot at the end is an empty label but we must not count its 0 byte twice. +} +procedure TNetDbTest.TestBuildPayloadSimpleEndDot; +var + Q: TQueryData; + R,el: Integer; +begin + // this is the expected length. Essentially, for each label, len(label)+1, + // then 4 bytes for the qclass and qtype, and 1 more for a 0 byte. + // rather than hardwire the length we calculate it so that no matter + // what the fake domain the test passes. + el := (Length(FAKEDOMAIN)+1)+(Length(FAKETLD)+1)+5; + R := BuildPayLoad(Q, FAKEFQDN+'.', DNSQRY_A, 1); + AssertEquals('Payload byte count wrong:',el, R); +end; + +{ +Test BuildPayload with a label that starts with a dot. This should be +rejected outright. +} +procedure TNetDbTest.TestBuildPayloadSimpleStartDot; +var + Q: TQueryData; + R: Integer; +begin + R := BuildPayLoad(Q, '.'+FAKEFQDN, DNSQRY_A, 1); + AssertEquals('Payload byte count wrong:',-1, R); +end; + +{ +Test BuildPayload with multiple dots (empty labels) in the middle of the domain +name. This should be rejected outright. +} +procedure TNetDbTest.TestBuildPayloadSimpleMultipleDot; +var + Q: TQueryData; + R: Integer; +begin + R := BuildPayLoad(Q, FAKEDOMAIN+'.....'+FAKETLD, DNSQRY_A, 1); + AssertEquals('Payload byte count wrong:',-1, R); +end; + +procedure TNetDbTest.TestDnsQueryUDP_A; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an A RR.', DNSQRY_A, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong A record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong A record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[1], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.5.1', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsQueryTCP_A; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an A RR.', DNSQRY_A, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong A record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong A record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[1], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.5.1', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_A; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an A RR.', DNSQRY_A, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong A record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong A record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[1], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.5.1', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_A; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an A RR.', DNSQRY_A, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong A record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong A record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[1], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.5.1', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsQueryUDP_AAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an AAAA RR.',DNSQRY_AAAA, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong AAAA record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong AAAA record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', HostAddrToStr6(ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::92E6:BAFF:FE44:FFBB', HostAddrToStr6(ip)); +end; + +procedure TNetDbTest.TestDnsQueryTCP_AAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an AAAA RR.',DNSQRY_AAAA, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong AAAA record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong AAAA record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[0], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::92E6:BAFF:FE44:FFBB', + HostAddrToStr6(ip)); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_AAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an AAAA RR.',DNSQRY_AAAA, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong AAAA record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong AAAA record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[0], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::92E6:BAFF:FE44:FFBB', + HostAddrToStr6(ip)); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_AAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an AAAA RR.',DNSQRY_AAAA, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertEquals('Wrong AAAA record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertEquals('Wrong AAAA record name for RR 1', FAKEFQDN, + RRArr[1].RRName); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[0], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], + qd.Payload, ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::92E6:BAFF:FE44:FFBB', + HostAddrToStr6(ip)); +end; + +procedure TNetDbTest.TestDnsQueryUDP_MX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + mxrec: TDNSRR_MX; + ip: THostAddr; + ip6: THostAddr6; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an MX RR.',DNSQRY_MX, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, mxrec)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + mxrec.exchange); + AssertEquals('Wrong MX preference', 10, mxrec.preference); + + AssertEquals('Should be 2 additional RR records.',2,NToHs(qd.h.arcount)); + RRArr := GetRRrecords(qd.Payload, ansstart, NToHs(qd.h.arcount)); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], qd.Payload, ip6)); + + AssertEquals('Wrong ip for A.', '172.16.27.238', HostAddrToStr(ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip6)); +end; + +procedure TNetDbTest.TestDnsQueryTCP_MX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + mxrec: TDNSRR_MX; + ip: THostAddr; + ip6: THostAddr6; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an MX RR.',DNSQRY_MX, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, mxrec)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + mxrec.exchange); + AssertEquals('Wrong MX preference', 10, mxrec.preference); + + AssertEquals('Should be 2 additional RR records.',2,NToHs(qd.h.arcount)); + RRArr := GetRRrecords(qd.Payload, ansstart, NToHs(qd.h.arcount)); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], qd.Payload, ip6)); + + AssertEquals('Wrong ip for A.', '172.16.27.238', HostAddrToStr(ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip6)); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_MX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + mxrec: TDNSRR_MX; + ip: THostAddr; + ip6: THostAddr6; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an MX RR.',DNSQRY_MX, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, mxrec)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + mxrec.exchange); + AssertEquals('Wrong MX preference', 10, mxrec.preference); + + AssertEquals('Should be 2 additional RR records.',2,NToHs(qd.h.arcount)); + RRArr := GetRRrecords(qd.Payload, ansstart, NToHs(qd.h.arcount)); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], qd.Payload, + ip6)); + + AssertEquals('Wrong ip for A.', '172.16.27.238', HostAddrToStr(ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip6)); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_MX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + mxrec: TDNSRR_MX; + ip: THostAddr; + ip6: THostAddr6; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an MX RR.',DNSQRY_MX, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, mxrec)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + mxrec.exchange); + AssertEquals('Wrong MX preference', 10, mxrec.preference); + + AssertEquals('Should be 2 additional RR records.',2,NToHs(qd.h.arcount)); + RRArr := GetRRrecords(qd.Payload, ansstart, NToHs(qd.h.arcount)); + AssertEquals('Wrong number of resource records.', 2, Length(RRArr)); + AssertEquals('RR 0 is not an A RR.',DNSQRY_A, RRarr[0].RRMeta.Atype); + AssertEquals('RR 1 is not an AAAA RR.', DNSQRY_AAAA, RRarr[1].RRMeta.Atype); + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertTrue('Did not get RR AAAA data.', DNSRRGetAAAA(RRArr[1], qd.Payload, + ip6)); + + AssertEquals('Wrong ip for A.', '172.16.27.238', HostAddrToStr(ip)); + AssertEquals('Wrong ip for AAAA.', 'FE80::3B92:3429:FF16:A3E4', + HostAddrToStr6(ip6)); +end; + +procedure TNetDbTest.TestDnsQueryUDP_SOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsQueryTCP_SOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_SOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_SOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsQueryUDP_CNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong CNAME record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryTCP_CNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong CNAME record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_CNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong CNAME record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_CNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong CNAME record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, + s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryUDP_NS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryTCP_NS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_NS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_NS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryUDP_PTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryTCP_PTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_PTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_PTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsQueryUDP_TXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +procedure TNetDbTest.TestDnsQueryTCP_TXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_TXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_TXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +procedure TNetDbTest.TestDnsQueryUDP_SRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +procedure TNetDbTest.TestDnsQueryTCP_SRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +procedure TNetDbTest.TestDnsQueryCompressUDP_SRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +procedure TNetDbTest.TestDnsQueryCompressTCP_SRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to compressed querydata', + BuildQueryData(fakeresp, qd, anslen, True)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + AssertEquals('Wrong record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +{ +This test is of debatable value, as it only detects truncation if the buffer +contents are zeroed which gives an invalid RR type. +} +procedure TNetDbTest.TestDnsQueryTruncateRR_UDP_A; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildTruncatedQueryData(fakeresp, qd, anslen,40)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + // the header says there are 2 A records, but it's a trap! + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + // truncation of buffer means this call returns 0 RRs. + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of RRs', 0, Length(RRArr)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // Change start position for RR[0] to end of buffer - 4 + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + qd.Payload[Length(qd.Payload)-1] := $AA; // sentinel marker we can look for + + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '0.0.0.170', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // Change start position for RR[0] to end of buffer - 3 + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 3); + AssertFalse('Got RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); +end; + +{ +Test that we read the AAAA right at the buffer edge, with the last byte +being a special value we can test for. +} +procedure TNetDbTest.TestDnsRRBufferEdgeAAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + // Change start position for RR[0] + RRArr[0].RDataSt := Length(qd.Payload) - SizeOf(THostAddr6); + qd.Payload[Length(qd.Payload)-1] := $AA; + AssertTrue('Got RR AAAA data.', DNSRRGetAAAA(RRArr[0], qd.Payload, ip)); + AssertEquals($AA, ip.u6_addr8[15]); +end; + +{ +Attempt to read an AAAA that goes past the end of the buffer. +} +procedure TNetDbTest.TestDNsRRBufferPastEdgeAAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + // Change start position for RR[0]. attempting to read 16 bytes + // from this position will pass the end of the buffer. + RRArr[0].RDataSt := Length(qd.Payload) - (SizeOf(THostAddr6)-1); + qd.Payload[Length(qd.Payload)-1] := $AA; + AssertFalse('Got RR AAAA data.', DNSRRGetAAAA(RRArr[0], qd.Payload, ip)); +end; + +{ +Test reading an MX RR that terminates on the last byte of the buffer. +} +procedure TNetDbTest.TestDnsRRBufferEdgeMX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + fmx: TDNSRR_MX; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // move the MX RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Got RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, fmx)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + fmx.exchange); + AssertEquals('Wrong MX preference', 10, fmx.preference); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeMX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + fmx: TDNSRR_MX; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // move the MX RR bytes to the end of the payload buffer. We omit the last + // 2 bytes of the MX to attempt to trick the code into reading past the buffer + // edge. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + AssertTrue('Got RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, fmx)); + // stringfromlabel should drop the last label, so the result should be just + // missing the tld. + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEDOMAIN, + fmx.exchange); + AssertEquals('Wrong MX preference', 10, fmx.preference); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeSOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + // move the SOA RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeSOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + // move the SOA RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-1); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-1)); + + AssertFalse('Got RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeSRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + // move the SRV RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeSRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + // move the SRV RR bytes to the end of the payload buffer. ensure that + // we're one byte short to try and trick the code into reading past the + // end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 1); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength - 1)); + + AssertFalse('Got RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeCNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + + // move the cname to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +{ +Test retrieving a cname when the actual string is longer than rdlength says it +is. The bytes in the payload buffer try to point past the end of the buffer. +} +procedure TNetDbTest.TestDnsRRBufferPastEdgeCNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + + // move the cname to the end of the buffer. we drop two bytes off the end of + // the cname, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEDOMAIN, s); +end; + +{ +Test retrieving an NS RR when it's at the end of the payload buffer. +} +procedure TNetDbTest.TestDnsRRBufferEdgeNS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // move the ns to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeNS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + + // move the ns to the end of the buffer. we drop two bytes off the end of + // the ns, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong NS.', 'fakens.'+FAKEDOMAIN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgePTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + + // move the ptr to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgePTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + + // move the ns to the end of the buffer. we drop two bytes off the end of + // the ns, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEDOMAIN, s); +end; + +{ +Test reading a text record right at the edge of the payload buffer. +} +procedure TNetDbTest.TestDnsRRBufferEdgeTXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart,oldstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // Move the text record to the end of the buffer + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +{ +Try reading a TXT record that points past the end of the payload buffer. +} +procedure TNetDbTest.TestDnsRRBufferPastEdgeTXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart,oldstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // Move the text record to the end of the buffer, cutting off the last + // 2 bytes. this means the length byte for the second string will point + // past the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength - 2)); + AssertFalse('Did not get RR TXT data.', + DNSRRGetText(RRArr[0], qd.Payload, s)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // Change start position for RR[0] to end of buffer - 4 + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + qd.Payload[Length(qd.Payload)-1] := $AA; // sentinel marker we can look for + AssertTrue('Did not get RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '0.0.0.170', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // Change start position for RR[0] to end of buffer - 3 + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 2); + AssertFalse('Got RR A data.', DNSRRGetA(RRArr[0], qd.Payload, ip)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPAAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + // Change start position for RR[0] + RRArr[0].RDataSt := Length(qd.Payload) - SizeOf(THostAddr6); + qd.Payload[Length(qd.Payload)-1] := $AA; + AssertTrue('Got RR AAAA data.', DNSRRGetAAAA(RRArr[0], qd.Payload, ip)); + AssertEquals($AA, ip.u6_addr8[15]); +end; + +procedure TNetDbTest.TestDNsRRBufferPastEdgeTCPAAAA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; + ip: THostAddr6; +begin + BuildFakeResponseAAAA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of AAAA records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + // Change start position for RR[0]. attempting to read 16 bytes + // from this position will pass the end of the buffer. + RRArr[0].RDataSt := Length(qd.Payload) - (SizeOf(THostAddr6)-1); + AssertFalse('Got RR AAAA data.', DNSRRGetAAAA(RRArr[0], qd.Payload, ip)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPMX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + fmx: TDNSRR_MX; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // move the MX RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Got RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, fmx)); + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEFQDN, + fmx.exchange); + AssertEquals('Wrong MX preference', 10, fmx.preference); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPMX; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + fmx: TDNSRR_MX; +begin + BuildFakeResponseMX(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of MX records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + + // move the MX RR bytes to the end of the payload buffer. We omit the last + // 2 bytes of the MX to attempt to trick the code into reading past the buffer + // edge. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + AssertTrue('Got RR MX data.', DNSRRGetMX(RRArr[0], qd.Payload, fmx)); + // stringfromlabel should drop the last label, so the result should be just + // missing the tld. + AssertEquals('Wrong MX hostname', 'mailer.'+FAKEDOMAIN, + fmx.exchange); + AssertEquals('Wrong MX preference', 10, fmx.preference); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPSOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + // move the SOA RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); + AssertEquals('Wrong mname hostname', 'mn.'+FAKEFQDN, + soarec.mname); + AssertEquals('Wrong rname hostname', 'rn.'+FAKEFQDN, + soarec.rname); + AssertEquals('Wrong SOA serial', 76543210, soarec.serial); + AssertEquals('Wrong SOA refresh', 123, soarec.refresh); + AssertEquals('Wrong SOA retry', 456, soarec.retry); + AssertEquals('Wrong SOA expire', 789, soarec.expire); + AssertEquals('Wrong SOA min', 60, soarec.min); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPSOA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + soarec: TDNSRR_SOA; +begin + BuildFakeResponseSOA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SOA records.', 1, qd.h.ancount); + + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SOA RR.',DNSQRY_SOA, RRarr[0].RRMeta.Atype); + + // move the SOA RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-1); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-1)); + + AssertFalse('Got RR SOA data.', DNSRRGetSOA(RRArr[0], qd.Payload, + soarec)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPSRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + // move the SRV RR bytes to the end of the payload buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); + AssertEquals('Wrong SRV priority', 22, srvrec.priority); + AssertEquals('Wrong SRV weight', 44, srvrec.weight); + AssertEquals('Wrong SRV port', 2201, srvrec.port); + + AssertEquals('Wrong SRV hostname', '_this._that._other', srvrec.target); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPSRV; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + srvrec: TDNSRR_SRV; +begin + BuildFakeResponseSRV(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of SRV records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an SRV RR.',DNSQRY_SRV, RRarr[0].RRMeta.Atype); + + // move the SRV RR bytes to the end of the payload buffer. ensure that + // we're one byte short to try and trick the code into reading past the + // end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 1); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength - 1)); + + AssertFalse('Got RR SRV data.', DNSRRGetSRV(RRArr[0], qd.Payload, + srvrec)); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPCNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + + // move the cname to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPCNAME; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseCNAME(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of CNAME records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an CNAME RR.',DNSQRY_CNAME, RRarr[0].RRMeta.Atype); + + // move the cname to the end of the buffer. we drop two bytes off the end of + // the cname, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR CNAME data.', DNSRRGetCNAME(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong CNAME.', 'fakecname.'+FAKEDOMAIN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPNS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong NS record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // move the ns to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong NS.', 'fakens.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPNS; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + + // move the ns to the end of the buffer. we drop two bytes off the end of + // the ns, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR NS data.', DNSRRGetNS(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong NS.', 'fakens.'+FAKEDOMAIN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPPTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + + // move the ptr to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEFQDN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPPTR; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; +begin + // the str passed in to this function doesn't really matter, but using + // a proper in-addr.arpa domain helps keep it clear what we're testing. + BuildFakeResponsePTR('0.5.0.127.in-addr.arpa', fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of PTR records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an PTR RR.',DNSQRY_PTR, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong PTR record name for RR 0', '0.5.0.127.in-addr.arpa', + RRArr[0].RRName); + + // move the ns to the end of the buffer. we drop two bytes off the end of + // the ns, because there's a 0 byte at the end of a label if not a ptr. + // now, the last label's size is greater than the number of bytes left in + // the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength-2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength-2)); + + // lie about the rdlength too! + Dec(RRArr[0].RRMeta.RDLength,2); + AssertTrue('Did not get RR PTR data.', DNSRRGetPTR(RRArr[0], qd.Payload, s)); + // last label will get removed, leaving just the domain part. + AssertEquals('Wrong PTR.', 'fakeptrans.'+FAKEDOMAIN, s); +end; + +procedure TNetDbTest.TestDnsRRBufferEdgeTCPTXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart,oldstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // Move the text record to the end of the buffer + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + AssertTrue('Did not get RR TXT data.', DNSRRGetText(RRArr[0], qd.Payload, s)); + AssertEquals( + 'v=spf1 mx a:lists.'+FAKEFQDN+'Always look on the bright side of life!', + s); +end; + +procedure TNetDbTest.TestDnsRRBufferPastEdgeTCPTXT; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart,oldstart: Word; + RRArr: TRRNameDataArray; + s: AnsiString; +begin + s := ''; + BuildFakeResponseTXT(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of TXT records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not a TXT RR.',DNSQRY_TXT, RRarr[0].RRMeta.Atype); + AssertEquals('Wrong TXT record name for RR 0', FAKEFQDN, + RRArr[0].RRName); + + // Move the text record to the end of the buffer, cutting off the last + // 2 bytes. this means the length byte for the second string will point + // past the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - (RRArr[0].RRMeta.RDLength - 2); + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, + (RRArr[0].RRMeta.RDLength - 2)); + AssertFalse('Did not get RR TXT data.', + DNSRRGetText(RRArr[0], qd.Payload, s)); +end; + +{ +Test that NextNameRR correctly reads an RR on the edge of the buffer. +} +procedure TNetDbTest.TestNextNameRREdgeA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + rrn: TRRNameData; + ip: THostAddr; + t: Cardinal; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + + // get an RR from its normal position. need this to calculate the length. + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, ansstart, rrn)); + + // calculate the size in bytes of the rr so we can copy it to the end + // of the payload buffer + t := (rrn.RDataSt + rrn.RRMeta.RDLength) - ansstart; + CopyBytesTo(qd.Payload,ansstart,Length(qd.Payload)-t, t); + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, Length(qd.Payload)-t, rrn)); + AssertEquals(DNSQRY_A, rrn.RRMeta.Atype); + AssertEquals(300, rrn.RRMeta.TTL); + AssertTrue(DNSRRGetA(rrn, qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); +end; + +{ +Try to trick NextNameRR into reading past the end of the payload buffer. +} +procedure TNetDbTest.TestNextNameRRPastEdgeA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + rrn: TRRNameData; + t: Cardinal; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + + // get an RR from its normal position. need this to calculate the length. + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, ansstart, rrn)); + + // calculate the size in bytes of the rr so we can copy it to the end + // of the payload buffer + t := (rrn.RDataSt + rrn.RRMeta.RDLength) - ansstart; + // copy the bytes, but leave off the last one. leave the rdlength unchanged. + CopyBytesTo(qd.Payload,ansstart,Length(qd.Payload)-(t-1), t-1); + AssertFalse('NextNameRR should fail.', + NextNameRR(qd.Payload, Length(qd.Payload)-(t-1), rrn)); +end; + +procedure TNetDbTest.TestNextNameRREdgeTCPA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + rrn: TRRNameData; + ip: THostAddr; + t: Cardinal; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + + // get an RR from its normal position. need this to calculate the length. + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, ansstart, rrn)); + + // calculate the size in bytes of the rr so we can copy it to the end + // of the payload buffer + t := (rrn.RDataSt + rrn.RRMeta.RDLength) - ansstart; + CopyBytesTo(qd.Payload,ansstart,Length(qd.Payload)-t, t); + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, Length(qd.Payload)-t, rrn)); + AssertEquals(DNSQRY_A, rrn.RRMeta.Atype); + AssertEquals(300, rrn.RRMeta.TTL); + AssertTrue(DNSRRGetA(rrn, qd.Payload, ip)); + AssertEquals('Wrong ip for A.', '127.0.0.1', HostAddrToStr(ip)); +end; + +procedure TNetDbTest.TestNextNameRRPastEdgeTCPA; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + rrn: TRRNameData; + t: Cardinal; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + + // get an RR from its normal position. need this to calculate the length. + AssertTrue('NextNameRR should succeed.', + NextNameRR(qd.Payload, ansstart, rrn)); + + // calculate the size in bytes of the rr so we can copy it to the end + // of the payload buffer + t := (rrn.RDataSt + rrn.RRMeta.RDLength) - ansstart; + // copy the bytes, but leave off the last one. leave the rdlength unchanged. + CopyBytesTo(qd.Payload,ansstart,Length(qd.Payload)-(t-1), t-1); + AssertFalse('NextNameRR should fail.', + NextNameRR(qd.Payload, Length(qd.Payload)-(t-1), rrn)); +end; + +{ +Call GetRRrecords with a start position past the end of the buffer. +} + +procedure TNetDbTest.TestGetRRrecordsInvalidStart; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := High(Word); + anslen := High(Word); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, anslen); + AssertEquals(0, Length(RRArr)); +end; + +procedure TNetDbTest.TestGetRRrecordsInvalidStartTCP; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart: Word; + RRArr: TRRNameDataArray; +begin + BuildFakeResponseA(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := High(Word); + anslen := High(Word); + AssertEquals('Wrong number of A records.', 2, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, anslen); + AssertEquals(0, Length(RRArr)); +end; + +procedure TNetDbTest.TestGetFixLenStrSimple; +const + s = 'another fine mess'; +var + buf: TBuffer; + pl: TPayload; + tr: TTextArray; + offset: Cardinal; + res: ShortString; +begin + tr[1] := s; + tr[2] := ''; + tr[3] := ''; + tr[4] := ''; + tr[5] := ''; + SetLength(buf, 1024); + offset := 0; + WriteTextRecAsRData(buf, offset, tr); + SetLength(buf, offset); + BufferToPayload(buf, pl); + // rdlength is word, so len byte for str is at offset 2 and str starts + // at offset 3. + GetFixlenStr(pl, 3, pl[2], res); + AssertEquals(s, res); +end; + +procedure TNetDbTest.TestGetFixLenStrSimpleTCP; +const + s = 'another fine mess'; +var + buf: TBuffer; + pl: TPayLoadTCP; + tr: TTextArray; + offset: Cardinal; + res: ShortString; +begin + tr[1] := s; + tr[2] := ''; + tr[3] := ''; + tr[4] := ''; + tr[5] := ''; + SetLength(buf, 1024); + offset := 0; + WriteTextRecAsRData(buf, offset, tr); + SetLength(buf, offset); + BufferToPayload(buf, pl); + // rdlength is word, so len byte for str is at offset 2 and str starts + // at offset 3. + GetFixlenStr(pl, 3, pl[2], res); + AssertEquals(s, res); +end; + +procedure TNetDbTest.TestGetFixLenStrSimpleAtEdge; +const + s = 'another fine mess'; +var + buf: TBuffer; + pl: TPayload; + tr: TTextArray; + offset,n: Cardinal; + res: ShortString; +begin + tr[1] := s; + tr[2] := ''; + tr[3] := ''; + tr[4] := ''; + tr[5] := ''; + SetLength(buf, Length(pl)); + offset := Length(pl) - (Length(s)+3); + n := offset+2; + WriteTextRecAsRData(buf, offset, tr); + SetLength(buf, offset); + BufferToPayload(buf, pl); + GetFixlenStr(pl, n+1, pl[n], res); + AssertEquals(s, res); +end; + +procedure TNetDbTest.TestGetFixLenStrSimpleTCPAtEdge; +const + s = 'another fine mess'; +var + buf: TBuffer; + pl: TPayLoadTCP; + tr: TTextArray; + offset,n: Cardinal; + res: ShortString; +begin + tr[1] := s; + tr[2] := ''; + tr[3] := ''; + tr[4] := ''; + tr[5] := ''; + SetLength(buf, Length(pl)); + offset := Length(pl) - (Length(s)+3); + n := offset+2; + WriteTextRecAsRData(buf, offset, tr); + SetLength(buf, offset); + BufferToPayload(buf, pl); + GetFixlenStr(pl, n+1, pl[n], res); + AssertEquals(s, res); +end; + +{ +Test GetFixLenStr where len would take string past edge of buffer. +} +procedure TNetDbTest.TestGetFixLenStrSimplePastEdge; +var + pl: TPayLoadTCP; + res: ShortString; +begin + pl[Length(pl) - 2] := 30; + pl[Length(pl) - 1] := Ord('a'); + GetFixlenStr(pl, Length(pl)-1, pl[Length(pl)-2], res); + AssertEquals('', res); +end; + +procedure TNetDbTest.TestGetFixLenStrSimpleTCPPastEdge; +var + pl: TPayLoadTCP; + res: ShortString; +begin + pl[Length(pl) - 2] := 30; + pl[Length(pl) - 1] := Ord('a'); + GetFixlenStr(pl, Length(pl)-1, pl[Length(pl)-2], res); + AssertEquals('', res); +end; + +{ + read a label at the end of the buffer where the last byte is a count + greater than 0. this is to try and trick stringfromlabel into reading past + the end of the buffer. +} +procedure TNetDbTest.TestStringFromLabelCountAsLastByte; +var + fakeresp: TFakeDNSResponse; + qd: TQueryData; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; + startpos: Longint; +begin + // we can use any of CNAME, NS or PTR because these RRs are just a single + // domain name or series of labels. + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + + // move the ns to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + // Set the last byte in the buffer to a high count + qd.Payload[Length(qd.Payload)-1] := 63; // must be less than 64 + + // need this var because stringfromlabel expects a longint that's a var type. + startpos := RRarr[0].RDataSt; + s := stringfromlabel(qd.Payload, startpos); + AssertEquals('fakens.'+FAKEFQDN, s); + AssertEquals(Length(qd.Payload), startpos); +end; + +procedure TNetDbTest.TestStringFromLabelCountAsLastByteTCP; +var + fakeresp: TFakeDNSResponse; + qd: TQueryDataLengthTCP; + anslen, ansstart, oldstart: Word; + RRArr: TRRNameDataArray; + s: TDNSDomainName; + startpos: Longint; +begin + // we can use any of CNAME, NS or PTR because these RRs are just a single + // domain name or series of labels. + BuildFakeResponseNS(FAKEFQDN, fakeresp); + AssertTrue('Unable to convert fake dns response to querydata', + BuildQueryData(fakeresp, qd, anslen)); + AssertTrue('CheckAnswer should return true.', CheckAnswer(qd.h,qd.h)); + ansstart := SkipAnsQueries(qd, anslen); + AssertEquals('Wrong number of NS records.', 1, qd.h.ancount); + RRArr := GetRRrecords(qd.Payload, ansstart, qd.h.ancount); + AssertEquals('Wrong number of resource records.', 1, Length(RRArr)); + AssertEquals('RR 0 is not an NS RR.',DNSQRY_NS, RRarr[0].RRMeta.Atype); + + // move the ns to the end of the buffer. + oldstart := RRArr[0].RDataSt; + RRArr[0].RDataSt := Length(qd.Payload) - RRArr[0].RRMeta.RDLength; + CopyBytesTo(qd.Payload, oldstart, RRArr[0].RDataSt, RRArr[0].RRMeta.RDLength); + + // Set the last byte in the buffer to a high count + qd.Payload[Length(qd.Payload)-1] := 63; // must be less than 64 + + // need this var because stringfromlabel expects a longint that's a var type. + startpos := RRarr[0].RDataSt; + s := stringfromlabel(qd.Payload, startpos); + AssertEquals('fakens.'+FAKEFQDN, s); + AssertEquals(Length(qd.Payload), startpos); +end; + +procedure TNetDbTest.TestStringFromLabelCompress; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayload; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // write same domain, this time we get compression. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + s := stringfromlabel(pl, offset2); + AssertEquals(FAKEFQDN,s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressTCP; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayLoadTCP; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // write same domain, this time we get compression. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + s := stringfromlabel(pl, offset2); + AssertEquals(FAKEFQDN,s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressWithUncompressedLabel; +var + buf: TBuffer; + dmbs: TDNSDomainByteStream; + offset: Cardinal; + so: Longint; + stt: TDomainCompressionTable; + len: Word; + pl: TPayload; + s: String; +begin + SetLength(buf, 1024); + SetLength(stt,0); + // compress table empty so no compression here. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + offset := 0; + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + + so := offset; + // should get compression on FAKEFQDN but label "foo" is written as full label. + dmbs := DomainNameToByteStream('foo.' + FAKEFQDN, stt); + len := CalcRdLength(dmbs); + // len is 4 for 'foo' (including its length byte) and 2 for the pointer. + AssertEquals(6, len); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + s := stringfromlabel(pl, so); + AssertEquals('foo.'+FAKEFQDN,s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressWithUncompressedLabelTCP; +var + buf: TBuffer; + dmbs: TDNSDomainByteStream; + offset: Cardinal; + so: Longint; + stt: TDomainCompressionTable; + len: Word; + pl: TPayLoadTCP; + s: String; +begin + SetLength(buf, 1024); + SetLength(stt,0); + // compress table empty so no compression here. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + offset := 0; + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + + so := offset; + // should get compression on FAKEFQDN but label "foo" is written as full label. + dmbs := DomainNameToByteStream('foo.' + FAKEFQDN, stt); + len := CalcRdLength(dmbs); + // len is 4 for 'foo' (including its length byte) and 2 for the pointer. + AssertEquals(6, len); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + s := stringfromlabel(pl, so); + AssertEquals('foo.'+FAKEFQDN,s); +end; + +{ +Test stringfromlabel with a compressed label at the end of the buffer. +} +procedure TNetDbTest.TestStringFromLabelCompressEndBuffer; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayload; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // write same domain, this time we get compression. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + + // write the pointer at the end of the payload buffer + offset := Length(pl) - 2; + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + + // read back the label. + offset2 := Length(pl) - 2; + s := stringfromlabel(pl, offset2); + AssertEquals(FAKEFQDN,s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressEndBufferTCP; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayLoadTCP; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, Length(pl)); + SetLength(stt,0); + offset := 0; + + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // write same domain, this time we get compression. + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + + // write the pointer at the end of the payload buffer + offset := Length(pl) - 2; + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + BufferToPayload(buf,pl); + + // read back the label. + offset2 := Length(pl) - 2; + s := stringfromlabel(pl, offset2); + AssertEquals(FAKEFQDN,s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressSplit; +var + pl: TPayload; + s: String; + offset: Longint; +begin + // fill the buffer with 'A' so that we'll know if stringfromlabel read any + // of it. + FillByte(pl, Length(pl), 65); + offset := Length(pl) - 1; + pl[offset] := 192; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressSplitTCP; +var + pl: TPayLoadTCP; + s: String; + offset: Longint; +begin + // fill the buffer with 'A' so that we'll know if stringfromlabel read any + // of it. + FillByte(pl, Length(pl), 65); + offset := Length(pl) - 1; + pl[offset] := 192; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressPtrFwd; +var + pl: TPayload; + s: String; + offset: Longint; + ptr: TDNSDomainPointer; +begin + FillByte(pl, Length(pl), 0); + Move('foo', pl[21], 3); + pl[20] := 3; + + ptr := GetDnsDomainPointer(32); // offset 20 + 12 for the header + offset := 0; + pl[offset] := ptr.b1; + pl[offset+1] := ptr.b2; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressPtrFwdTCP; +var + pl: TPayLoadTCP; + s: String; + offset: Longint; + ptr: TDNSDomainPointer; +begin + FillByte(pl, Length(pl), 0); + Move('foo', pl[21], 3); + pl[20] := 3; + + ptr := GetDnsDomainPointer(32); // offset 20 + 12 for the header + offset := 0; + pl[offset] := ptr.b1; + pl[offset+1] := ptr.b2; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressAllPtrStart; +var + pl: TPayload; + s: String; + offset: Longint; +begin + FillByte(pl, Length(pl), 192); + offset := 0; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelCompressAllPtrStartTCP; +var + pl: TPayLoadTCP; + s: String; + offset: Longint; +begin + FillByte(pl, Length(pl), 192); + offset := 0; + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +{ +Test what happens when pointer is 0. +} +procedure TNetDbTest.TestStringFromLabelCompressedZero; +var + pl: TPayLoad; + s: String; + offset: Longint; + ptr: TDNSDomainPointer; +begin + FillByte(pl, Length(pl), 0); + pl[0] := 1; + pl[1] := Ord('a'); + ptr := GetDnsDomainPointer(0); + offset := 5; + pl[offset] := ptr.b1; + pl[offset+1] := ptr.b2; + + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +{ +Test what happens when pointer is 0. +} +procedure TNetDbTest.TestStringFromLabelCompressedZeroTCP; +var + pl: TPayLoadTCP; + s: String; + offset: Longint; + ptr: TDNSDomainPointer; +begin + FillByte(pl, Length(pl), 0); + pl[0] := 1; + pl[1] := Ord('a'); + ptr := GetDnsDomainPointer(0); + offset := 5; + pl[offset] := ptr.b1; + pl[offset+1] := ptr.b2; + + s := stringfromlabel(pl, offset); + AssertEquals('', s); +end; + +procedure TNetDbTest.TestStringFromLabelInfiniteLoop; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayload; + s: String; + dmbs: TDNSDomainByteStream; + ptr: TDNSDomainPointer; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + ptr := GetDnsDomainPointer(12); + + // offset now points to 0 byte at end of label. We're overwriting that + // 0 so that stringfromlabel will be tricked into a loop. + Dec(offset); + Move(ptr.ba, buf[offset], 2); + + BufferToPayload(buf,pl); + offset2 := 0; + s := stringfromlabel(pl, offset2); + // if stringfromlabel returns at all then the test passed. +end; + +procedure TNetDbTest.TestStringFromLabelInfiniteLoopTCP; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayLoadTCP; + s: String; + dmbs: TDNSDomainByteStream; + ptr: TDNSDomainPointer; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(FAKEFQDN, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + ptr := GetDnsDomainPointer(12); + + // offset now points to 0 byte at end of label. We're overwriting that + // 0 so that stringfromlabel will be tricked into a loop. + Dec(offset); + Move(ptr.ba, buf[offset], 2); + + BufferToPayload(buf,pl); + offset2 := 0; + s := stringfromlabel(pl, offset2); + // if stringfromlabel returns at all then the test passed. +end; + +procedure TNetDbTest.TestCompressShortDomain; +const + shortdomain = 'a.b'; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayload; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(shortdomain, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // second str is compressed + dmbs := DomainNameToByteStream(shortdomain, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + + BufferToPayload(buf,pl); + s := stringfromlabel(pl, offset2); + AssertEquals(shortdomain, s); +end; + +procedure TNetDbTest.TestCompressShortDomainTCP; +const + shortdomain = 'a.b'; +var + buf: TBuffer; + stt: TDomainCompressionTable; + offset: Cardinal; + offset2: Longint; + pl: TPayLoadTCP; + s: String; + dmbs: TDNSDomainByteStream; +begin + SetLength(buf, 1024); + SetLength(stt,0); + offset := 0; + // initial str is uncompressed because compress table empty + dmbs := DomainNameToByteStream(shortdomain, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + offset2 := offset; + // second str is compressed + dmbs := DomainNameToByteStream(shortdomain, stt); + WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs); + + BufferToPayload(buf,pl); + s := stringfromlabel(pl, offset2); + AssertEquals(shortdomain, s); +end; + +procedure TNetDbTest.SetUp; +begin + tsl := TStringList.Create; +end; + +procedure TNetDbTest.TearDown; +begin + tsl.Free; +end; + +procedure TNetDbTest.CopyBytesTo(var buf: TPayLoad; startidx, destidx, + count: Word); +begin + // no tests for overlapping source and dest. + if ((startidx+count) > Length(buf)) or ((destidx+count) > Length(buf)) then + exit; + Move(buf[startidx], buf[destidx], count); +end; + +procedure TNetDbTest.CopyBytesTo(var buf: TPayLoadTCP; startidx, destidx, + count: Word); +begin + // no tests for overlapping source and dest. + if ((startidx+count) > Length(buf)) or ((destidx+count) > Length(buf)) then + exit; + Move(buf[startidx], buf[destidx], count); +end; + +function TNetDbTest.WriteNumToBuffer(var buf: TBuffer; var offset: Cardinal; + val: Word): Word; +begin + Result := 0; + if (offset + SizeOf(val)) > Length(buf) then exit; + Move(HToNs(val), buf[offset], SizeOf(val)); + Inc(offset, SizeOf(val)); + Result := SizeOf(val); +end; + +function TNetDbTest.WriteNumToBuffer(var buf: TBuffer; var offset: Cardinal; + val: Cardinal): Word; +begin + Result := 0; + if (offset + SizeOf(val)) > Length(buf) then exit; + Move(HToNl(val), buf[offset], SizeOf(val)); + Inc(offset, SizeOf(val)); + Result := SizeOf(val); +end; + +{ +Write a number to the buffer without converting it to network byte order. +} +function TNetDbTest.WriteNumToBufferN(var buf: TBuffer; var offset: Cardinal; + val: Word): Word; +begin + Result := 0; + if (offset + SizeOf(val)) > Length(buf) then exit; + Move(val, buf[offset], SizeOf(val)); + Inc(offset, SizeOf(val)); + Result := SizeOf(val); +end; + +{ +Write a number to the buffer without converting it to network byte order. +} +function TNetDbTest.WriteNumToBufferN(var buf: TBuffer; var offset: Cardinal; + val: Cardinal): Word; +begin + Result := 0; + if (offset + SizeOf(val)) > Length(buf) then exit; + Move(val, buf[offset], SizeOf(val)); + Inc(offset, SizeOf(val)); + Result := SizeOf(val); +end; + +{ +Write an RR to the byte buffer. No compression of domain names will occur. +} +function TNetDbTest.WriteRRToBuffer(var buf: TBuffer; var offset: Cardinal; + rr: TFakeRR): Word; +var + s,etw: Word; + dmbs: TDNSDomainByteStream; + res: TRDataWriteRes; +begin + etw := 0; + s := offset; + // write the RR Name + dmbs := DomainNameToByteStream(rr.RRName); + etw := CalcRdLength(dmbs); + if WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs) < etw + then + Fail('Cannot write RR name to buffer at offset '+ inttostr(offset)); + + if (offset + SizeOf(rr.Atype) + SizeOf(rr.AClass) + SizeOf(rr.TTL)) > + Length(buf) + then + Fail('Not enough space to add RR type,class,ttl at offset '+ inttostr(offset)); + + // Write the RR type, class and TTL. + WriteNumToBuffer(buf, offset,rr.Atype); + WriteNumToBuffer(buf, offset, rr.AClass); + WriteNumToBuffer(buf, offset, rr.TTL); + + // now the RR data, which is type specific. Each type-specific method + // also writes the RDLength word, so we have to account for 2 additional + // bytes. + case rr.Atype of + DNSQRY_A: + res := WriteAasRData(buf, offset, rr.ip); + DNSQRY_AAAA: + res := WriteAAAAasRData(buf, offset, rr.ip6); + DNSQRY_SOA: + res := WriteSOAasRData(buf, offset, rr.fsoa); + DNSQRY_MX: + res := WriteMXAsRData(buf, offset, rr.fmx); + DNSQRY_NS: + begin + dmbs := DomainNameToByteStream(rr.nsh); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_PTR: + begin + dmbs := DomainNameToByteStream(rr.nsh); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_CNAME: + begin + dmbs := DomainNameToByteStream(rr.cn); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_TXT: + res := WriteTextRecAsRData(buf, offset, rr.txtarr); + DNSQRY_SRV: + res := WriteSRVasRData(buf, offset, rr.fsrv); + else + Fail('Called to handle RR type '+inttostr(rr.Atype)+ + ' but no code to handle it.'); + end; + + if res.bw < res.etw then + Fail('Unable to write RR of type ' +inttostr(RR.Atype) + + ', name "' + rr.RRName + '" to buffer at offset '+inttostr(offset)+ + '. Wrote '+inttostr(res.bw)+' bytes, expected to write '+ + inttostr(res.etw)+' bytes.'); + + Result := offset - s; +end; + +{ +Write an RR to the output buffer, with compression of domain names turned on. +} +function TNetDbTest.WriteRRToBuffer(var buf: TBuffer; var offset: Cardinal; + rr: TFakeRR; var ctbl: TDomainCompressionTable): Word; +var + s, etw: Word; + dmbs: TDNSDomainByteStream; + res: TRDataWriteRes; +begin + etw := 0; + s := offset; + // write the RR Name + dmbs := DomainNameToByteStream(rr.RRName, ctbl); + etw := CalcRdLength(dmbs); + if WriteDNSDomainByteStreamToBuffer(buf, offset, dmbs) < etw + then + Fail('Cannot write RR name to buffer at offset '+ inttostr(offset)); + + if (offset + SizeOf(rr.Atype) + SizeOf(rr.AClass) + SizeOf(rr.TTL)) > + Length(buf) + then + Fail('Not enough space to add RR type,class,ttl at offset '+ inttostr(offset)); + + // Write the RR type, class and TTL. + WriteNumToBuffer(buf, offset,rr.Atype); + WriteNumToBuffer(buf, offset, rr.AClass); + WriteNumToBuffer(buf, offset, rr.TTL); + + // now the RR data, which is type specific. Each type-specific method + // also writes the RDLength word, so we have to account for 2 additional + // bytes. + case rr.Atype of + DNSQRY_A: + begin + res := WriteAasRData(buf, offset, rr.ip); + end; + DNSQRY_AAAA: + begin + res := WriteAAAAasRData(buf, offset, rr.ip6); + end; + DNSQRY_SOA: + begin + res := WriteSOAasRData(buf, offset, rr.fsoa); + end; + DNSQRY_MX: + begin + res := WriteMXAsRData(buf, offset, rr.fmx, ctbl); + end; + DNSQRY_NS: + begin + dmbs := DomainNameToByteStream(rr.nsh, ctbl); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_PTR: + begin + dmbs := DomainNameToByteStream(rr.nsh, ctbl); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_CNAME: + begin + dmbs := DomainNameToByteStream(rr.cn, ctbl); + res := WriteDomainAsRdata(buf,offset,dmbs); + end; + DNSQRY_TXT: + begin + res := WriteTextRecAsRData(buf, offset, rr.txtarr); + end; + DNSQRY_SRV: + begin + res := WriteSRVasRData(buf, offset, rr.fsrv); + end; + else + Fail('Called to handle RR type '+inttostr(rr.Atype)+ + ' but no code to handle it.'); + end; + + if res.bw < res.etw then + Fail('Unable to write RR of type ' +inttostr(RR.Atype) + + ', name "' + rr.RRName + '" to buffer at offset '+inttostr(offset)+ + '. Wrote '+inttostr(res.bw)+' bytes, expected to write '+ + inttostr(res.etw)+' bytes.'); + + Result := offset - s; +end; + +{ +Turn a fake DNS response into a payload buffer. This is a byte buffer minus the +DNS header. That is, the buffer begins with the question part of the response, +after which comes the RRs of the answers, authority, and additional sections. +} +function TNetDbTest.FakeDNSResponseToByteBuffer(fdr: TFakeDNSResponse; out + buf: TBuffer; compress: Boolean): Cardinal; +var + offset: Cardinal; + rr: TFakeRR; + dbs: TDNSDomainByteStream; +begin + // plenty of room for our test responses. could precalculate this, but there's + // no benefit. The return value of this function is the length of the + // DNS reply, which we get for free since we have to track our offset into + // the buffer as we write it. + SetLength(buf, 2048); + offset := 0; + + if compress then + dbs := DomainNameToByteStream(fdr.qry.nm,fdr.strtable) + else + dbs := DomainNameToByteStream(fdr.qry.nm); + + // The question section consists of the dns query name, the qtype and + // qclass. + if WriteDNSDomainByteStreamToBuffer(buf, offset, dbs) < CalcRdLength(dbs) + then + Fail('Cannot write name to buffer at offset '+ inttostr(offset)); + + WriteNumToBuffer(buf, offset, fdr.qry.qtype); + WriteNumToBuffer(buf, offset, fdr.qry.qclass); + + // Now the answer sections. + for rr in fdr.answers do + if compress then + WriteRRToBuffer(buf, offset, rr, fdr.strtable) + else + WriteRRToBuffer(buf, offset, rr); + for rr in fdr.authority do + if compress then + WriteRRToBuffer(buf, offset, rr, fdr.strtable) + else + WriteRRToBuffer(buf, offset, rr); + for rr in fdr.additional do + if compress then + WriteRRToBuffer(buf, offset, rr, fdr.strtable) + else + WriteRRToBuffer(buf, offset, rr); + + SetLength(buf, offset); + Result := offset; +end; + +{ +Generate a TPayload buffer, a fixed-length array of byte, from the TBuffer +type, which is a variable-length array of byte. +} +function TNetDbTest.BufferToPayload(const buf: TBuffer; + out pl: TPayload): Boolean; +begin + Result := False; + FillChar(pl,Length(pl),0); + Move(buf[0], pl[0], Min(Length(pl),Length(buf))); + Result := True; +end; + +function TNetDbTest.BufferToPayload(const buf: TBuffer; + out pl: TPayLoadTCP): Boolean; +begin + Result := False; + FillChar(pl,Length(pl),0); + Move(buf[0], pl[0], Min(Length(pl),Length(buf))); + Result := True; +end; + +function TNetDbTest.BuildQueryData(fdr: TFakeDNSResponse; out qd: TQueryData; + out qlen: Word; Compress: Boolean = False): Boolean; +var + buf: TBuffer; +begin + qlen := FakeDNSResponseToByteBuffer(fdr, buf, Compress); + qd.h.ancount := HToNs(fdr.hdr.ancount); + qd.h.arcount := HToNs(fdr.hdr.arcount); + qd.h.nscount := HToNs(fdr.hdr.nscount); + qd.h.qdcount := HToNs(fdr.hdr.qdcount); + qd.h.flags1 := fdr.hdr.flags1; + qd.h.flags2 := fdr.hdr.flags2; + qd.h.id[0] := fdr.hdr.id[0]; + qd.h.id[1] := fdr.hdr.id[1]; + Result := BufferToPayload(buf, qd.Payload); +end; + +function TNetDbTest.BuildQueryData(fdr: TFakeDNSResponse; out + qd: TQueryDataLengthTCP; out qlen: Word; Compress: Boolean = False): Boolean; +var + buf: TBuffer; +begin + qlen := FakeDNSResponseToByteBuffer(fdr, buf, Compress); + qd.h.ancount := HToNs(fdr.hdr.ancount); + qd.h.arcount := HToNs(fdr.hdr.arcount); + qd.h.nscount := HToNs(fdr.hdr.nscount); + qd.h.qdcount := HToNs(fdr.hdr.qdcount); + qd.h.flags1 := fdr.hdr.flags1; + qd.h.flags2 := fdr.hdr.flags2; + qd.h.id[0] := fdr.hdr.id[0]; + qd.h.id[1] := fdr.hdr.id[1]; + Result := BufferToPayload(buf, qd.Payload); +end; + +{ +Create a deliberately invalid DNS response to test our API's ability to cope +with invalid data without causing memory corruption. + +After building a valid DNS response as normal, we truncate it at the given +offset.} +function TNetDbTest.BuildTruncatedQueryData(fdr: TFakeDNSResponse; out + qd: TQueryData; out qlen: Word; truncoffset: Word): Boolean; +var + buf: TBuffer; +begin + qlen := FakeDNSResponseToByteBuffer(fdr, buf); + qd.h.ancount := HToNs(fdr.hdr.ancount); + qd.h.arcount := HToNs(fdr.hdr.arcount); + qd.h.nscount := HToNs(fdr.hdr.nscount); + qd.h.qdcount := HToNs(fdr.hdr.qdcount); + qd.h.flags1 := fdr.hdr.flags1; + qd.h.flags2 := fdr.hdr.flags2; + qd.h.id[0] := fdr.hdr.id[0]; + qd.h.id[1] := fdr.hdr.id[1]; + SetLength(buf, truncoffset); + Result := BufferToPayload(buf, qd.Payload); +end; + +initialization + + RegisterTest(TNetDbTest); +end. + diff --git a/avx512-0037785/packages/fcl-net/tests/tresolvertests.pp b/avx512-0037785/packages/fcl-net/tests/tresolvertests.pp new file mode 100644 index 0000000000..9892dc446b --- /dev/null +++ b/avx512-0037785/packages/fcl-net/tests/tresolvertests.pp @@ -0,0 +1,28 @@ +program tresolvertests; + +{$mode objfpc}{$H+} + +uses + Classes, consoletestrunner, netdbtest; + +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:='resolvertests'; + Application.Run; + Application.Free; +end. diff --git a/avx512-0037785/packages/fcl-passrc/src/pasresolver.pp b/avx512-0037785/packages/fcl-passrc/src/pasresolver.pp index 9fe78b10ff..54f9110705 100644 --- a/avx512-0037785/packages/fcl-passrc/src/pasresolver.pp +++ b/avx512-0037785/packages/fcl-passrc/src/pasresolver.pp @@ -3937,10 +3937,16 @@ end; { EPasResolve } procedure EPasResolve.SetPasElement(AValue: TPasElement); +var + Old: TPasElement; begin if FPasElement=AValue then Exit; - if PasElement<>nil then + Old:=FPasElement; + if Old<>nil then + begin + Old:=nil; PasElement.Release{$IFDEF CheckPasTreeRefCount}('EPasResolve.SetPasElement'){$ENDIF}; + end; FPasElement:=AValue; if PasElement<>nil then PasElement.AddRef{$IFDEF CheckPasTreeRefCount}('EPasResolve.SetPasElement'){$ENDIF}; @@ -7526,11 +7532,13 @@ procedure TPasResolver.FinishExceptOnExpr; var El: TPasImplExceptOn; ResolvedType: TPasResolverResult; + TypeEl: TPasType; begin CheckTopScope(TPasExceptOnScope); El:=TPasImplExceptOn(FTopScope.Element); - ComputeElement(El.TypeEl,ResolvedType,[rcType]); - CheckIsClass(El.TypeEl,ResolvedType); + TypeEl:=El.TypeEl; + ComputeElement(TypeEl,ResolvedType,[rcType]); + CheckIsClass(TypeEl,ResolvedType); end; procedure TPasResolver.FinishExceptOnStatement; @@ -9049,7 +9057,7 @@ begin CurEl:=nil; if not SameText(RightStr(AttrName,length('Attribute')),'Attribute') then begin - // first search AttrName+'Attibute' + // first search AttrName+'Attribute' CurEl:=FindFirstEl(AttrName+'Attribute',Data,NameExpr); end; // then search the name @@ -9164,12 +9172,14 @@ var FindData: TPRFindData; Ref: TResolvedReference; ResolvedEl: TPasResolverResult; + Section: TPasSection; + Scope: TPasIdentifierScope; + ScopeIdent: TPasIdentifier; begin Expr:=El.NameExpr; if Expr<>nil then begin ResolveExpr(Expr,rraRead); - //ResolveGlobalSymbol(Expr); ComputeElement(Expr,ResolvedEl,[rcConstant]); DeclEl:=ResolvedEl.IdentEl; if DeclEl=nil then @@ -9189,9 +9199,21 @@ begin CheckFoundElement(FindData,Ref); end; + if DeclEl is TPasProcedure then + begin + Section:=DeclEl.Parent as TPasSection; + Scope:=Section.CustomData as TPasIdentifierScope; + ScopeIdent:=Scope.FindLocalIdentifier(DeclEl.Name); + if (ScopeIdent=nil) then + RaiseNotYetImplemented(20210106103001,El,GetObjPath(DeclEl)); + if ScopeIdent.NextSameIdentifier<>nil then + RaiseMsg(20210106103320,nCantDetermineWhichOverloadedFunctionToCall, + sCantDetermineWhichOverloadedFunctionToCall,[],El); + end; + // check index and name CheckConstExpr(El.ExportIndex,[revkInt,revkUInt],'integer'); - CheckConstExpr(El.ExportName,[revkString,revkUnicodeString],'string'); + CheckConstExpr(El.ExportName,revkAllStrings,'string'); end; procedure TPasResolver.FinishProcParamAccess(ProcType: TPasProcedureType; @@ -12243,6 +12265,7 @@ begin writeln('TPasResolver.AddExportSymbol ',GetObjName(El)); {$ENDIF} // Note: export symbol is not added to scope + if El=nil then ; end; procedure TPasResolver.AddEnumType(El: TPasEnumType); @@ -18740,54 +18763,67 @@ function TPasResolver.BI_InExclude_OnGetCallCompatibility( // check params of built in proc 'include' var Params: TParamsExpr; - Param: TPasExpr; - ParamResolved: TPasResolverResult; + Param0, Param1: TPasExpr; + Param0Resolved, Param1Resolved: TPasResolverResult; EnumType: TPasEnumType; C: TClass; + LoTypeEl: TPasType; + RgType: TPasRangeType; begin if not CheckBuiltInMinParamCount(Proc,Expr,2,RaiseOnError) then exit(cIncompatible); Params:=TParamsExpr(Expr); - // first param: set variable + // first Param0: set variable // todo set of int, set of char, set of bool - Param:=Params.Params[0]; - ComputeElement(Param,ParamResolved,[rcNoImplicitProc]); + Param0:=Params.Params[0]; + ComputeElement(Param0,Param0Resolved,[rcNoImplicitProc]); + Param1:=Params.Params[1]; + ComputeElement(Param1,Param1Resolved,[]); + EnumType:=nil; - if ([rrfReadable,rrfWritable]*ParamResolved.Flags=[rrfReadable,rrfWritable]) - and (ParamResolved.IdentEl<>nil) then + RgType:=nil; + if ([rrfReadable,rrfWritable]*Param0Resolved.Flags=[rrfReadable,rrfWritable]) + and (Param0Resolved.IdentEl<>nil) then begin - C:=ParamResolved.IdentEl.ClassType; + C:=Param0Resolved.IdentEl.ClassType; if (C.InheritsFrom(TPasVariable) or (C=TPasArgument) or (C=TPasResultElement)) then begin - if (ParamResolved.BaseType=btSet) - and (ParamResolved.LoTypeEl is TPasEnumType) then - EnumType:=TPasEnumType(ParamResolved.LoTypeEl); + if Param0Resolved.BaseType=btSet then + begin + LoTypeEl:=Param0Resolved.LoTypeEl; + if LoTypeEl.ClassType=TPasEnumType then + begin + EnumType:=TPasEnumType(LoTypeEl); + if (not (rrfReadable in Param0Resolved.Flags)) + or (Param0Resolved.LoTypeEl<>EnumType) then + begin + if RaiseOnError then + RaiseIncompatibleType(20210201225926,nIncompatibleTypeArgNo, + ['2'],Param0Resolved.LoTypeEl,EnumType,Param0); + exit(cIncompatible); + end; + end + else if LoTypeEl.ClassType=TPasRangeType then + begin + RgType:=TPasRangeType(LoTypeEl); + ComputeElement(RgType.RangeExpr.left,Param0Resolved,[]); + Result:=CheckAssignResCompatibility(Param0Resolved,Param1Resolved,Param1,RaiseOnError); + end; + end; end; end; - if EnumType=nil then + if (EnumType=nil) and (RgType=nil) then begin {$IFDEF VerbosePasResolver} - writeln('TPasResolver.OnGetCallCompatibility_InExclude ',GetResolverResultDbg(ParamResolved)); + writeln('TPasResolver.OnGetCallCompatibility_InExclude ',GetResolverResultDbg(Param0Resolved)); {$ENDIF} - exit(CheckRaiseTypeArgNo(20170216152301,1,Param,ParamResolved, + exit(CheckRaiseTypeArgNo(20170216152301,1,Param0,Param0Resolved, 'variable of set of enumtype',RaiseOnError)); end; - // second param: enum - Param:=Params.Params[1]; - ComputeElement(Param,ParamResolved,[]); - if (not (rrfReadable in ParamResolved.Flags)) - or (ParamResolved.LoTypeEl<>EnumType) then - begin - if RaiseOnError then - RaiseIncompatibleType(20170216152302,nIncompatibleTypeArgNo, - ['2'],ParamResolved.LoTypeEl,EnumType,Param); - exit(cIncompatible); - end; - Result:=CheckBuiltInMaxParamCount(Proc,Params,2,RaiseOnError); end; @@ -19113,19 +19149,19 @@ begin exit(cIncompatible); Params:=TParamsExpr(Expr); - // first param: bool, enum or char + // first param: bool, integer, enum or char Param:=Params.Params[0]; ComputeElement(Param,ParamResolved,[]); Result:=cIncompatible; if rrfReadable in ParamResolved.Flags then begin - if ParamResolved.BaseType in (btAllBooleans+btAllChars) then + if ParamResolved.BaseType in btArrayRangeTypes then Result:=cExact else if (ParamResolved.BaseType=btContext) and (ParamResolved.LoTypeEl is TPasEnumType) then Result:=cExact else if ParamResolved.BaseType=btRange then begin - if ParamResolved.SubType in btAllBooleans+btAllChars then + if ParamResolved.SubType in btArrayRangeTypes then Result:=cExact else if ParamResolved.SubType=btContext then begin @@ -21318,7 +21354,7 @@ procedure TPasResolver.CheckFoundElement( // Call this method after finding an element by searching the scopes. function IsFieldInheritingConst(aRef: TResolvedReference): boolean; - // returns true of aRef is a TPasVariable that inherits its const from parent. + // returns true if aRef is a TPasVariable that inherits its const from parent. // For example // type TRecord = record // a: word; // inherits const @@ -27564,6 +27600,21 @@ procedure TPasResolver.ComputeElement(El: TPasElement; out end; end; + procedure ComputeExportSymbol(ExpSymbol: TPasExportSymbol); + var + Ref: TResolvedReference; + begin + if ExpSymbol.CustomData is TResolvedReference then + begin + Ref:=TResolvedReference(El.CustomData); + ComputeElement(Ref.Declaration,ResolvedEl,Flags+[rcNoImplicitProc],StartEl); + end + else if ExpSymbol.NameExpr<>nil then + ComputeElement(ExpSymbol.NameExpr,ResolvedEl,Flags,StartEl) + else + RaiseNotYetImplemented(20210106225512,ExpSymbol); + end; + var DeclEl: TPasElement; ElClass: TClass; @@ -27946,6 +27997,8 @@ begin ComputeSpecializeType(TPasSpecializeType(El)) else if ElClass=TInlineSpecializeExpr then ComputeElement(TInlineSpecializeExpr(El).NameExpr,ResolvedEl,Flags,StartEl) + else if ElClass=TPasExportSymbol then + ComputeExportSymbol(TPasExportSymbol(El)) else RaiseNotYetImplemented(20160922163705,El); {$IF defined(nodejs) and defined(VerbosePasResolver)} diff --git a/avx512-0037785/packages/fcl-passrc/src/pparser.pp b/avx512-0037785/packages/fcl-passrc/src/pparser.pp index 59e54088b1..a85d01bb5d 100644 --- a/avx512-0037785/packages/fcl-passrc/src/pparser.pp +++ b/avx512-0037785/packages/fcl-passrc/src/pparser.pp @@ -3142,10 +3142,10 @@ begin FinishedModule; finally if HasFinished then - begin - Module.Release{$IFDEF CheckPasTreeRefCount}('TPasPackage.Modules'){$ENDIF}; + //begin + //Module.Release{$IFDEF CheckPasTreeRefCount}('TPasPackage.Modules'){$ENDIF}; FCurModule:=nil; // clear module if there is an error or finished parsing - end; + //end; end; end; @@ -6001,10 +6001,23 @@ var function CloseBlock: boolean; // true if parent reached var C: TPasImplBlockClass; + NeedUnget: Boolean; begin C:=TPasImplBlockClass(CurBlock.ClassType); if C=TPasImplExceptOn then - Engine.FinishScope(stExceptOnStatement,CurBlock) + begin + Engine.FinishScope(stExceptOnStatement,CurBlock); + NeedUnget:=CurToken=tkSemicolon; + if NeedUnget then + NextToken; + if (CurToken in [tkend,tkelse]) + or ((CurToken=tkIdentifier) and (lowercase(CurTokenString)='on')) then + // ok + else + ParseExcExpectedAorB('end','on'); + if NeedUnget then + UngetToken; + end else if C=TPasImplWithDo then Engine.FinishScope(stWithExpr,CurBlock); CurBlock:=CurBlock.Parent as TPasImplBlock; @@ -6063,6 +6076,7 @@ var TypeEl: TPasType; ImplRaise: TPasImplRaise; VarEl: TPasVariable; + ImplExceptOn: TPasImplExceptOn; begin NewImplElement:=nil; @@ -6486,6 +6500,8 @@ begin // ParseExc; CheckStatementCanStart; + //writeln('TPasParser.ParseStatement ',CurToken,' ',CurTokenString); + // On is usable as an identifier if lowerCase(CurTokenText)='on' then begin @@ -6496,31 +6512,33 @@ begin begin SrcPos:=CurTokenPos; ExpectIdentifier; - El:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock,SrcPos)); + ImplExceptOn:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock,SrcPos)); + El:=ImplExceptOn; SrcPos:=CurSourcePos; Name:=CurTokenString; NextToken; + //writeln('TPasParser.ParseStatement ',CurToken,' ',CurTokenString); //writeln('ON t=',Name,' Token=',CurTokenText); if CurToken=tkColon then begin // the first expression was the variable name NextToken; - TypeEl:=ParseSimpleType(El,SrcPos,''); - TPasImplExceptOn(El).TypeEl:=TypeEl; - VarEl:=TPasVariable(CreateElement(TPasVariable,Name,El,SrcPos)); - TPasImplExceptOn(El).VarEl:=VarEl; + TypeEl:=ParseSimpleType(ImplExceptOn,SrcPos,''); + ImplExceptOn.TypeEl:=TypeEl; + VarEl:=TPasVariable(CreateElement(TPasVariable,Name,ImplExceptOn,SrcPos)); + ImplExceptOn.VarEl:=VarEl; VarEl.VarType:=TypeEl; TypeEl.AddRef{$IFDEF CheckPasTreeRefCount}('TPasVariable.VarType'){$ENDIF}; - if TypeEl.Parent=El then + if TypeEl.Parent=ImplExceptOn then TypeEl.Parent:=VarEl; end else begin UngetToken; - TPasImplExceptOn(El).TypeEl:=ParseSimpleType(El,SrcPos,''); + ImplExceptOn.TypeEl:=ParseSimpleType(ImplExceptOn,SrcPos,''); end; - Engine.FinishScope(stExceptOnExpr,El); - CreateBlock(TPasImplExceptOn(El)); + Engine.FinishScope(stExceptOnExpr,ImplExceptOn); + CreateBlock(ImplExceptOn); El:=nil; ExpectToken(tkDo); end else diff --git a/avx512-0037785/packages/fcl-passrc/tests/tcresolver.pas b/avx512-0037785/packages/fcl-passrc/tests/tcresolver.pas index 587d86c3bf..d7ac1df835 100644 --- a/avx512-0037785/packages/fcl-passrc/tests/tcresolver.pas +++ b/avx512-0037785/packages/fcl-passrc/tests/tcresolver.pas @@ -345,6 +345,7 @@ type Procedure TestTryStatement; Procedure TestTryExceptOnNonTypeFail; Procedure TestTryExceptOnNonClassFail; + Procedure TestTryStatementMissingOnFail; Procedure TestRaiseNonVarFail; Procedure TestRaiseNonClassFail; Procedure TestRaiseDescendant; @@ -986,8 +987,8 @@ type Procedure TestLibrary_ExportFunc_IndexStringFail; Procedure TestLibrary_ExportVar; // ToDo Procedure TestLibrary_Initialization_Finalization; - Procedure TestLibrary_ExportFuncOverloadFail; // ToDo - // ToDo Procedure TestLibrary_UnitExports; + Procedure TestLibrary_ExportFuncOverloadFail; + Procedure TestLibrary_UnitExports; end; function LinesToStr(Args: array of const): string; @@ -1736,6 +1737,8 @@ begin end; ok:=true; end; + on E: Exception do + Fail('Expected EPasResolve but got '+E.ClassName); end; AssertEquals('Missing resolver error {'+Msg+'} ('+IntToStr(MsgNumber)+')',true,ok); end; @@ -1756,6 +1759,8 @@ begin MsgNumber,Parser.LastMsgNumber); ok:=true; end; + on E: Exception do + Fail('Expected EParserError but got '+E.ClassName); end; AssertEquals('Missing parser error '+Msg+' ('+IntToStr(MsgNumber)+')',true,ok); end; @@ -3354,8 +3359,11 @@ begin ' i2: TInt2;', 'begin', ' i:=i2;', - ' if i=i2 then ;']); + ' if i=i2 then ;', + ' i:=ord(i);', + '']); ParseProgram; + CheckResolverUnexpectedHints; end; procedure TTestResolver.TestIntegerRangeHighLowerLowFail; @@ -4225,7 +4233,9 @@ begin ' s:= {#s3_set}[3..4];', ' s:= {#s4_set}[Three];', ' if 3 in a then ;', - ' s:=c;']); + ' s:=c;', + ' Include(s,3);', + '']); ParseProgram; CheckParamsExpr_pkSet_Markers; CheckResolverUnexpectedHints; @@ -5414,6 +5424,23 @@ begin CheckResolverException('class expected, but Longint found',nXExpectedButYFound); end; +procedure TTestResolver.TestTryStatementMissingOnFail; +begin + StartProgram(true,[supTObject]); + Add([ + 'procedure Run;', + 'begin', + ' try', + ' except', + ' on TObject do ;', + ' Run;', + ' end;', + 'end;', + 'begin', + '']); + CheckParserException('Expected "end" or "on"',nParserExpectToken2Error); +end; + procedure TTestResolver.TestRaiseNonVarFail; begin StartProgram(false); @@ -18836,8 +18863,6 @@ end; procedure TTestResolver.TestLibrary_ExportFuncOverloadFail; begin - exit; - StartLibrary(false); Add([ 'procedure Run(w: word); overload;', @@ -18850,7 +18875,24 @@ begin ' Run,', ' afile.run;', 'begin']); - CheckResolverException('The symbol cannot be exported from a library',123); + CheckResolverException(sCantDetermineWhichOverloadedFunctionToCall, + nCantDetermineWhichOverloadedFunctionToCall); +end; + +procedure TTestResolver.TestLibrary_UnitExports; +begin + StartUnit(false); + Add([ + 'interface' , + 'procedure Run;', + 'implementation', + 'procedure Run;', + 'begin', + 'end;', + 'exports', + ' Run;', + '']); + ParseUnit; end; initialization diff --git a/avx512-0037785/packages/fcl-registry/fpmake.pp b/avx512-0037785/packages/fcl-registry/fpmake.pp index b398893b4e..f9a71a0ca0 100644 --- a/avx512-0037785/packages/fcl-registry/fpmake.pp +++ b/avx512-0037785/packages/fcl-registry/fpmake.pp @@ -46,8 +46,7 @@ begin T:=P.Targets.AddUnit('xmlreg.pp'); P.ExamplePath.Add('examples'); - P.Targets.AddExampleProgram('tests/testbasics.pp'); - P.Targets.AddExampleProgram('tests/regtestframework.pp'); + P.Targets.AddExampleProgram('tests/tregtestframework.pp'); // 'tests/Makefile // 'tests/Makefile.fpc diff --git a/avx512-0037785/packages/fcl-registry/src/regini.inc b/avx512-0037785/packages/fcl-registry/src/regini.inc index 665e24ba4e..4163a57c9b 100644 --- a/avx512-0037785/packages/fcl-registry/src/regini.inc +++ b/avx512-0037785/packages/fcl-registry/src/regini.inc @@ -293,31 +293,36 @@ end; function TRegIniFile.OpenSection(const Section: string; CreateSection : Boolean = false): boolean; var - k: HKEY; - S : String; - + s: string; begin - S:=Section; - If (S<>'') and (S[1] = '\') then - Delete(S,1,1); - if CreateSection and (S<>'') then - CreateKey('\'+CurrentPath+'\'+S); - if S <> '' then - k:=GetKey('\'+CurrentPath+'\'+S) - else - k:=GetKey('\'+CurrentPath); - if k = 0 then - begin - Result:=False; - exit; + ASSERT(fOldCurKey = 0); + if Section <> '' then begin + fOldCurKey:=CurrentKey; + fOldCurPath:=CurrentPath; + // Detach the current key to prevent its closing in OpenKey() + SetCurrentKey(0); + if Section[1] = '\' then + s:=Section + else + s:='\' + string(fOldCurPath) + '\' + Section; + Result:=OpenKey(s, CreateSection); + if not Result then begin + // Restore on error + SetCurrentKey(fOldCurKey); + fOldCurKey:=0; + fOldCurPath:=''; end; - SetCurrentKey(k); - Result:=True; + end + else + Result:=True; end; procedure TRegIniFile.CloseSection; begin - CloseKey(CurrentKey); - fCurrentKey:=0; + if fOldCurKey <> 0 then begin + ChangeKey(fOldCurKey, fOldCurPath); + fOldCurKey:=0; + fOldCurPath:=''; + end; end; diff --git a/avx512-0037785/packages/fcl-registry/src/registry.pp b/avx512-0037785/packages/fcl-registry/src/registry.pp index 7f11182b05..91177376e1 100644 --- a/avx512-0037785/packages/fcl-registry/src/registry.pp +++ b/avx512-0037785/packages/fcl-registry/src/registry.pp @@ -202,6 +202,8 @@ type fFileName : String; fPath : String; fPreferStringValues: Boolean; + fOldCurKey : HKEY; + fOldCurPath : UnicodeString; function OpenSection(const Section: string; CreateSection : Boolean = false): boolean; procedure CloseSection; public @@ -266,6 +268,7 @@ type procedure DeleteKey(const Section, Name: String); override; procedure UpdateFile; override; function ValueExists(const Section, Ident: string): Boolean; override; + function SectionExists(const Section: string): Boolean; override; property RegIniFile: TRegIniFile read FRegIniFile; end{$ifdef XMLREG}deprecated 'Use TRegistry instead. Will be removed in 4.0'{$endif} platform; @@ -1125,13 +1128,18 @@ end; function TRegistryIniFile.ValueExists(const Section, Ident: string): Boolean; begin - with FRegInifile do - if OpenSection(Section) then - try - Result:=FRegInifile.ValueExists(Ident); - finally - CloseSection; - end; + Result:=FRegInifile.OpenSection(Section); + if Result then + try + Result:=FRegInifile.ValueExists(Ident); + finally + FRegInifile.CloseSection; + end; +end; + +function TRegistryIniFile.SectionExists(const Section: string): Boolean; +begin + Result:=FRegIniFile.KeyExists(Section); end; {$ifdef XMLREG} diff --git a/avx512-0037785/packages/fcl-registry/src/winreg.inc b/avx512-0037785/packages/fcl-registry/src/winreg.inc index f4efdc88d3..3fa014d1a3 100644 --- a/avx512-0037785/packages/fcl-registry/src/winreg.inc +++ b/avx512-0037785/packages/fcl-registry/src/winreg.inc @@ -81,7 +81,28 @@ function TRegistry.DeleteKey(const Key: UnicodeString): Boolean; Var u: UnicodeString; + subkeys: TUnicodeStringArray; + k, old: HKEY; + i: integer; begin + old:=fCurrentKey; + k:=GetKey(Key); + if k <> 0 then + begin + fCurrentKey:=k; + try + subkeys:=GetKeyNames; + for i:=0 to High(subkeys) do + begin + Result:=DeleteKey(subkeys[i]); + if not Result then + exit; + end; + finally + fCurrentKey:=old; + CloseKey(k); + end; + end; u:=PRepKey(Key); FLastError:=RegDeleteKeyW(GetBaseKey(RelativeKey(Key)),PWideChar(u)); Result:=FLastError=ERROR_SUCCESS; diff --git a/avx512-0037785/packages/fcl-registry/src/xmlreg.pp b/avx512-0037785/packages/fcl-registry/src/xmlreg.pp index 7b661e5922..961c599878 100644 --- a/avx512-0037785/packages/fcl-registry/src/xmlreg.pp +++ b/avx512-0037785/packages/fcl-registry/src/xmlreg.pp @@ -235,23 +235,13 @@ end; Function TXmlRegistry.DeleteKey(KeyPath : UnicodeString) : Boolean; Var - N, Curr : TDomElement; - Node: TDOMNode; + N : TDomElement; begin N:=FindKey(KeyPath); Result:=(N<>Nil); If Result then begin - //if a key has subkeys, result shall be false and nothing shall be deleted - Curr:=N; - Node:=Curr.FirstChild; - While Assigned(Node) do - begin - If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName=SKey) then - Exit(False); - Node:=Node.NextSibling; - end; (N.ParentNode as TDomElement).RemoveChild(N); FDirty:=True; MaybeFlush; @@ -269,6 +259,8 @@ begin Result:=(Length(KeyPath)>0); If Not Result then Exit; + If (KeyPath[1] in ['/','\']) then + FCurrentElement:=Nil; KeyPath:=NormalizeKey(KeyPath); If (FCurrentElement<>nil) then begin @@ -917,6 +909,8 @@ begin Result:=Nil; If (Length(S)=0) then Exit; + if S[1] in ['/','\'] then + FCurrentElement:=nil; S:=NormalizeKey(S); If (FCurrentElement<>nil) then begin diff --git a/avx512-0037785/packages/fcl-registry/tests/Makefile b/avx512-0037785/packages/fcl-registry/tests/Makefile index fbf4d80011..e4c98af0e8 100644 --- a/avx512-0037785/packages/fcl-registry/tests/Makefile +++ b/avx512-0037785/packages/fcl-registry/tests/Makefile @@ -350,316 +350,316 @@ endif override PACKAGE_NAME=fcl PACKAGEDIR_MAIN:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl/Makefile.fpc,$(PACKAGESDIR)))))) ifeq ($(FULL_TARGET),i386-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-go32v2) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-win32) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-os2) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-freebsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-beos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-haiku) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-solaris) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-netware) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-openbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-wdosx) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-darwin) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-emx) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-watcom) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-netwlibc) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-wince) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-symbian) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-nativent) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-iphonesim) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i386-aros) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-amiga) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-atari) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-palmos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-macosclassic) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),m68k-sinclairql) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-amiga) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-macosclassic) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-darwin) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-morphos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-wii) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc-aix) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),sparc-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),sparc-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),sparc-solaris) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),sparc-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-freebsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-haiku) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-solaris) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-openbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-darwin) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-win64) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-iphonesim) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-aros) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),x86_64-dragonfly) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-netbsd) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-palmos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-wince) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-gba) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-nds) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-symbian) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-aros) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-freertos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),arm-ios) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc64-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc64-darwin) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc64-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),powerpc64-aix) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),avr-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),armeb-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),armeb-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),mips-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),mipsel-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),mipsel-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),mipsel-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),mips64el-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),jvm-java) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),jvm-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i8086-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i8086-msdos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),i8086-win16) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),aarch64-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),aarch64-darwin) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),aarch64-win64) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),aarch64-android) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),aarch64-ios) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),wasm-wasm) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),sparc64-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),riscv32-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),riscv32-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),riscv64-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),riscv64-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),xtensa-linux) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),xtensa-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),xtensa-freertos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),z80-embedded) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),z80-zxspectrum) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),z80-msxdos) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif ifeq ($(FULL_TARGET),z80-amstradcpc) -override TARGET_EXAMPLES+=regtestframework +override TARGET_EXAMPLES+=tregtestframework endif override INSTALL_FPCPACKAGE=y ifdef REQUIRE_UNITSDIR diff --git a/avx512-0037785/packages/fcl-registry/tests/Makefile.fpc b/avx512-0037785/packages/fcl-registry/tests/Makefile.fpc index 724f61968b..7293b10223 100644 --- a/avx512-0037785/packages/fcl-registry/tests/Makefile.fpc +++ b/avx512-0037785/packages/fcl-registry/tests/Makefile.fpc @@ -1,12 +1,12 @@ #
-# Makefile.fpc for DB TestFramework
+# Makefile.fpc for Registry TestFramework
#
[package]
main=fcl
[target]
-examples=regtestframework
+examples=tregtestframework
[install]
fpcpackage=y
diff --git a/avx512-0037785/packages/fcl-registry/tests/tcxmlreg.pp b/avx512-0037785/packages/fcl-registry/tests/regtcxmlreg.pp index 273a09ac8e..2de0ddb4fe 100644 --- a/avx512-0037785/packages/fcl-registry/tests/tcxmlreg.pp +++ b/avx512-0037785/packages/fcl-registry/tests/regtcxmlreg.pp @@ -1,4 +1,4 @@ -unit tcxmlreg; +unit regtcxmlreg; {$mode objfpc}{$H+} @@ -39,6 +39,7 @@ end; procedure TTestXMLRegistry.TearDown; begin FreeAndNil(FXMLReg); + DeleteFile('test.xml'); inherited TearDown; end; @@ -93,13 +94,13 @@ begin SetLength(S1,100); For I:=0 to 99 do S1[I]:=i; - XMLReg.SetValueData('b',dtBinary,S1[1],Length(S1)); + XMLReg.SetValueData('b',dtBinary,S1[0],Length(S1)); XMLReg.Flush; - DS:=SizeOf(S1) div 4; + DS:=Length(S1) div 4; SetLength(S2,DS); For I:=0 to DS-1 do S2[I]:=i; - AssertEquals('Cannot read, buffer size too small',False,XMLReg.GetValueData('b',dt,S2[1],ds)); + AssertEquals('Cannot read, buffer size too small',False,XMLReg.GetValueData('b',dt,S2[0],DS)); AssertTrue('Correct data type reported',dt=dtBinary); AssertEquals('Correct data buffer size reported',Length(S1),DS); end; diff --git a/avx512-0037785/packages/fcl-registry/tests/testbasics.pp b/avx512-0037785/packages/fcl-registry/tests/regtestbasics.pp index dfe4eb193b..bddc3bcd17 100644 --- a/avx512-0037785/packages/fcl-registry/tests/testbasics.pp +++ b/avx512-0037785/packages/fcl-registry/tests/regtestbasics.pp @@ -1,4 +1,4 @@ -unit TestBasics; +unit RegTestBasics; {$IFDEF FPC} {$mode objfpc}{$H+} @@ -21,7 +21,6 @@ type procedure TestSimpleWinRegistry; procedure TestDoubleWrite; procedure bug16395; - procedure TestAdv; procedure TestStringList; Procedure TestInt64; Procedure TestDeleteSubkey; @@ -30,11 +29,7 @@ type implementation uses - registry -{$ifdef windows} - , tregistry2 -{$endif windows} - ; + registry; { TTestBasics } @@ -167,13 +162,6 @@ begin DeleteUserXmlFile; end; -procedure TTestBasics.TestAdv; -begin -{$ifdef windows} - DoRegTest2; -{$endif windows} -end; - Procedure TTestBasics.TestStringList; Var @@ -278,7 +266,7 @@ begin AssertTrue(format('OpenKey(''%s'') failed.',[Base]),B); B := R.DeleteKey('One'); - AssertFalse(format('DeleteKey(''%s'') should have failed, but it succeeded.',[OneFull]),B); + AssertTrue(format('DeleteKey(''%s'') should have succeeded, but it failed.',[OneFull]),B); finally R.Free; CleanUp(ExceptObject <> nil); diff --git a/avx512-0037785/packages/fcl-registry/tests/tregistry2.pp b/avx512-0037785/packages/fcl-registry/tests/tregistry2.pp index 7cc6a24411..e0ca983ae3 100644 --- a/avx512-0037785/packages/fcl-registry/tests/tregistry2.pp +++ b/avx512-0037785/packages/fcl-registry/tests/tregistry2.pp @@ -1,33 +1,47 @@ -{$ifdef FPC} {$mode delphi} {$endif} -unit tregistry2; - -interface +{ %TARGET=win32,win64,wince,linux,solaris,openbsd } -procedure DoRegTest2; +{ + This unit tests mostly TRegIniFile to work properly and be Delphi compatible. + This test also runs on non-Windows platforms where XML registry is used. + Please keep this test Delphi compatible. +} -implementation +{$ifdef FPC} {$mode delphi} {$endif} +uses +{$ifdef unix} + cwstring, +{$endif unix} + SysUtils, Classes, registry; -uses Windows, SysUtils, Classes, registry; +{$ifdef FPC} + {$WARN implicit_string_cast_loss off} + {$WARN symbol_deprecated off} +{$endif FPC} const STestRegPath = 'Software\FPC-RegTest'; procedure TestFailed(ErrCode: integer); begin - raise Exception.Create('Test FAILED. Error code: ' + IntToStr(ErrCode)); + writeln('Test FAILED. Error code: ' + IntToStr(ErrCode)); + Halt(ErrCode); end; -procedure ClearReg; +procedure ClearReg(const KeyName: string = ''); begin with TRegistry.Create do try - DeleteKey(STestRegPath + '\1'); DeleteKey(STestRegPath); finally Free; end; end; +function NormPath(const s: string): string; +begin + Result:=StringReplace(s, '/', '\', [rfReplaceAll]); +end; + procedure DoRegTest2; var reg: TRegistry; @@ -36,33 +50,47 @@ var sl: TStringList; begin ClearReg; - reg:=TRegistry.Create; try - if not reg.OpenKey(STestRegPath, True) then - TestFailed(1); - if reg.CurrentPath <> STestRegPath then - TestFailed(2); - reg.WriteString('Item1', '1'); - if not reg.OpenKey('\' + STestRegPath + '\1', True) then - TestFailed(3); - reg.WriteString('Item2', '2'); - if reg.CurrentPath <> STestRegPath + '\1' then - TestFailed(5); - reg.CloseKey; - if reg.CurrentPath <> '' then - TestFailed(6); + reg:=TRegistry.Create; + try + { The test key must be deleted by ClearReg() } + if reg.KeyExists(STestRegPath) then + TestFailed(1); + if reg.OpenKey(STestRegPath, False) then + TestFailed(2); + + if not reg.OpenKey(STestRegPath, True) then + TestFailed(5); + if NormPath(reg.CurrentPath) <> STestRegPath then + TestFailed(6); + reg.WriteString('Item1', '1'); + if not reg.OpenKey('\' + STestRegPath + '\1', True) then + TestFailed(10); + reg.WriteString('Item2', '2'); + if NormPath(reg.CurrentPath) <> STestRegPath + '\1' then + TestFailed(15); + reg.CloseKey; + if NormPath(reg.CurrentPath) <> '' then + TestFailed(20); + if reg.KeyExists(STestRegPath + '\' + STestRegPath) then + TestFailed(21); + finally + reg.Free; + end; ri:=TRegIniFile.Create(STestRegPath); with ri do try if ReadString('', 'Item1', '') <> '1' then - TestFailed(10); + TestFailed(101); if ReadString('1', 'Item2', '') <> '2' then - TestFailed(11); + TestFailed(105); + if NormPath(ri.CurrentPath) <> STestRegPath then + TestFailed(110); if ReadString('', 'Item1', '') <> '1' then - TestFailed(12); + TestFailed(115); if not ValueExists('Item1') then - TestFailed(13); + TestFailed(120); WriteInteger('1', 'Item3', 3); @@ -70,44 +98,133 @@ begin try ReadSectionValues('1', sl); if sl.Count <> 2 then - TestFailed(14); + TestFailed(125); if sl.Values['Item2'] <> '2' then - TestFailed(15); + TestFailed(130); if sl.Values['Item3'] <> '3' then - TestFailed(16); + TestFailed(135); finally sl.Free; end; WriteInteger('', 'Item4', 4); - if GetDataType('Item4') <> rdString then - TestFailed(17); + WriteInteger('', 'Item41', 41); + WriteInteger('', 'Item42', 42); + if GetDataType('Item4') <> rdString then + TestFailed(140); + if ReadString('', 'Item41', '') <> '41' then + TestFailed(141); + if ReadString('', 'Item42', '') <> '42' then + TestFailed(142); + finally + Free; + end; + + { \ at the beginning of the path must be accepted } + ri:=TRegIniFile.Create('\' + STestRegPath); + with ri do + try + if ReadString('', 'Item1', '') <> '1' then + TestFailed(145); finally Free; end; + { Write to non-existing key must work } + ri:=TRegIniFile.Create(STestRegPath + '\2\3\4'); + with ri do + try + if FileName <> NormPath(CurrentPath) then + TestFailed(147); + if CurrentKey = 0 then + TestFailed(148); + WriteInteger('', 'Item5', 5); + WriteInteger('5', 'Item6', 6); + if ReadInteger('', 'Item5', 0) <> 5 then + TestFailed(150); + if ReadInteger('5', 'Item6', 0) <> 6 then + TestFailed(160); + finally + Free; + end; + + rini:=TRegistryIniFile.Create(STestRegPath); with rini do try if ReadString('', 'Item1', '') <> '1' then - TestFailed(20); + TestFailed(201); + { \ is not allowed as a section name } + if ReadString('\', 'Item1', '') = '1' then + TestFailed(202); if ReadString('1', 'Item2', '') <> '2' then - TestFailed(21); + TestFailed(205); + { Trailing \ is allowed } + if ReadString('1\', 'Item2', '') <> '2' then + TestFailed(206); if ReadString('', 'Item1', '') <> '1' then - TestFailed(22); + TestFailed(210); if not ValueExists('', 'Item4') then - TestFailed(23); + TestFailed(215); if not ValueExists('1', 'Item2') then - TestFailed(24); + TestFailed(220); + if ReadInteger('2\3\4\5', 'Item6', 0) <> 6 then + TestFailed(225); + if ReadInteger('2\3\4', 'Item5', 0) <> 5 then + TestFailed(230); + + EraseSection('2'); + if SectionExists('2\3') then + TestFailed(245); + if ValueExists('2\3\4', 'Item5') then + TestFailed(240); + + WriteString('2\3\4', 'Item10', '10'); + if ReadInteger('2\3\4', 'Item10', 0) <> 10 then + TestFailed(245); + + { Check access via a full path } + if not SectionExists('\' + STestRegPath) then + TestFailed(250); + if ReadInteger('\2\3\4', 'Item10', 0) = 10 then + TestFailed(255); + if ReadInteger('\' + STestRegPath + '\2\3\4', 'Item10', 0) <> 10 then + TestFailed(260); finally Free; end; finally - reg.Free; ClearReg; end; + + { Test if all test keys have been deleted by ClearReg() } + reg:=TRegistry.Create; + try + if reg.KeyExists(STestRegPath) then + TestFailed(501); + if reg.OpenKey(STestRegPath, False) then + TestFailed(502); + if reg.OpenKey(STestRegPath + '\2', False) then + TestFailed(503); + finally + reg.Free; + end; +end; + +procedure DeleteUserXmlFile; +begin +{$ifdef FPC} + DeleteFile(Includetrailingpathdelimiter(GetAppConfigDir(False))+'reg.xml'); + RemoveDir(GetAppConfigDir(False)); +{$endif FPC} end; +begin + try + DoRegTest2; + finally + DeleteUserXmlFile; + end; end. diff --git a/avx512-0037785/packages/fcl-registry/tests/regtestframework.pp b/avx512-0037785/packages/fcl-registry/tests/tregtestframework.pp index 49c3222a34..f8420857a3 100644 --- a/avx512-0037785/packages/fcl-registry/tests/regtestframework.pp +++ b/avx512-0037785/packages/fcl-registry/tests/tregtestframework.pp @@ -1,34 +1,35 @@ -program regtestframework;
-
-{$IFDEF FPC}
-{$mode objfpc}{$H+}
-{$ENDIF}
-
-{$IFDEF WINDOWS}
-{$APPTYPE CONSOLE}
-{$ENDIF}
-
-uses
- {$ifdef unix}
- cwstring,
- {$endif}
- SysUtils,
- fpcunit, testreport, testregistry, consoletestrunner,
-// Units wich contains the tests
- tcxmlreg,
- testbasics;
-
-Var
- A : TTestRunner;
-
-begin
- DefaultFormat:=fPlain;
- DefaultRunAllTests:=True;
- A:=TTestRunner.Create(Nil);
- try
- A.Initialize;
- A.Run;
- finally
- A.Free;
- end;
-end.
+{ %TARGET=win32,win64,wince,linux,solaris,openbsd } +program tregtestframework; + +{$IFDEF FPC} +{$mode objfpc}{$H+} +{$ENDIF} + +{$IFDEF WINDOWS} +{$APPTYPE CONSOLE} +{$ENDIF} + +uses + {$ifdef unix} + cwstring, + {$endif} + SysUtils, + fpcunit, testreport, testregistry, consoletestrunner, +// Units wich contains the tests + regtcxmlreg, + regtestbasics; + +Var + A : TTestRunner; + +begin + DefaultFormat:=fPlain; + DefaultRunAllTests:=True; + A:=TTestRunner.Create(Nil); + try + A.Initialize; + A.Run; + finally + A.Free; + end; +end. diff --git a/avx512-0037785/packages/fcl-stl/src/gdeque.pp b/avx512-0037785/packages/fcl-stl/src/gdeque.pp index c620188000..ac106e5581 100644 --- a/avx512-0037785/packages/fcl-stl/src/gdeque.pp +++ b/avx512-0037785/packages/fcl-stl/src/gdeque.pp @@ -14,6 +14,11 @@ unit gdeque; +{ + Implements a generic double ended queue. + (See: https://en.wikipedia.org/wiki/Double-ended_queue) +} + interface type @@ -30,10 +35,18 @@ type procedure SetValue(position:SizeUInt; value:T);inline; function GetValue(position:SizeUInt):T;inline; function GetMutable(position:SizeUInt):PT;inline; - procedure IncreaseCapacity();inline; + procedure IncreaseCapacity(); + protected + procedure MoveSimpleData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); + procedure MoveManagedData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); + procedure MoveData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); + procedure ClearSingleDataEntry(Index: SizeUInt); virtual; + procedure ClearData; virtual; + property Data: TArr read FData; public function Size():SizeUInt;inline; constructor Create(); + destructor Destroy(); override; Procedure Clear; procedure PushBack(value:T);inline; procedure PushFront(value:T);inline; @@ -59,8 +72,15 @@ begin FStart:=0; end; +destructor TDeque.Destroy(); +begin + Clear; + inherited Destroy; +end; + procedure TDeque.Clear; begin + ClearData; FDataSize:=0; FStart:=0; end; @@ -87,6 +107,7 @@ procedure TDeque.PopFront();inline; begin if(FDataSize>0) then begin + ClearSingleDataEntry(FStart); inc(FStart); dec(FDataSize); if(FStart=FCapacity) then @@ -97,7 +118,10 @@ end; procedure TDeque.PopBack();inline; begin if(FDataSize>0) then + begin + ClearSingleDataEntry((FStart+FDataSize-1)mod FCapacity); dec(FDataSize); + end; end; procedure TDeque.PushFront(value:T);inline; @@ -127,6 +151,7 @@ end; procedure TDeque.SetValue(position:SizeUInt; value:T);inline; begin Assert(position < size, 'Deque access out of range'); + ClearSingleDataEntry((FStart+position)mod FCapacity); FData[(FStart+position)mod FCapacity]:=value; end; @@ -142,7 +167,68 @@ begin GetMutable:=@FData[(FStart+position) mod FCapacity]; end; -procedure TDeque.IncreaseCapacity;inline; + +procedure TDeque.MoveSimpleData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); +begin + Move(FData[StartIndex], FData[StartIndex+Offset], NrElems*SizeOf(T)); + if Offset>0 then + FillChar(FData[StartIndex], NrElems*SizeOf(T), 0) + else + FillChar(FData[StartIndex+NrElems+Offset], -Offset*SizeOf(T), 0); +end; + +procedure TDeque.MoveManagedData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); +var + i: SizeUInt; +begin + //since we always move blocks where Abs(Offset)>=NrElems, there is no need for + //2 seperate loops (1 for ngeative and 1 for positive Offsett) + for i := 0 to NrElems-1 do + begin + Finalize(FData[StartIndex+i+Offset]); + FData[StartIndex+i+Offset] := FData[StartIndex+i]; + Finalize(FData[StartIndex+i]); + FillChar(FData[StartIndex+i], SizeOf(T), 0); + end; +end; + +procedure TDeque.MoveData(StartIndex: SizeUInt; Offset: SizeInt; NrElems: SizeUInt); +begin + if IsManagedType(T) then + MoveManagedData(StartIndex, Offset, NrElems) + else + MoveSimpleData(StartIndex, Offset, NrElems); +end; + +procedure TDeque.ClearSingleDataEntry(Index: SizeUInt); +begin + if IsManagedType(T) then + begin + Finalize(FData[Index]); + FillChar(FData[Index], SizeOf(T), 0); + end + else + FData[Index] := default(T); +end; + +procedure TDeque.ClearData; +var + i: SizeUint; +begin + if IsManagedType(T) then + for i := Low(FData) to High(FData) do + Finalize(FData[i]); + FillChar(FData[Low(FData)], SizeUInt(Length(FData))*SizeOf(T), 0); +end; + +procedure TDeque.IncreaseCapacity; + function Min(const A,B: SizeUInt): SizeUInt; inline; //no need to drag in the entire Math unit ;-) + begin + if (A<B) then + Result:=A + else + Result:=B; + end; const // if size is small, multiply by 2; // if size bigger but <256M, inc by 1/8*size; @@ -151,7 +237,7 @@ const cSizeBig = 256*1024*1024; var i,OldEnd, - DataSize:SizeUInt; + DataSize,CurLast,EmptyElems,Elems:SizeUInt; begin OldEnd:=FCapacity; DataSize:=FCapacity*SizeOf(T); @@ -165,11 +251,26 @@ begin FCapacity:=FCapacity+FCapacity div 8 else FCapacity:=FCapacity+FCapacity div 16; - SetLength(FData, FCapacity); if (FStart>0) then - for i:=0 to FStart-1 do - FData[OldEnd+i]:=FData[i]; + begin + if (FCapacity-OldEnd>=FStart) then //we have room to move all items in one go + begin + MoveData(0, OldEnd ,FStart) + end + else + begin //we have to move things around in chunks: we have more data in front of FStart than we have newly created unused elements + CurLast := OldEnd-1; + EmptyElems:=FCapacity-1-CurLast; + while (FStart>0) do + begin + Elems := Min(EmptyElems, FStart); + MoveData(0, CurLast+1, Elems); + MoveData(Elems, -Elems, FCapacity-Elems); + Dec(FStart, Elems); + end; + end; + end; end; procedure TDeque.Reserve(cap:SizeUInt);inline; diff --git a/avx512-0037785/packages/fpmkunit/src/fpmkunit.pp b/avx512-0037785/packages/fpmkunit/src/fpmkunit.pp index f858a90c65..d8bc9a4016 100644 --- a/avx512-0037785/packages/fpmkunit/src/fpmkunit.pp +++ b/avx512-0037785/packages/fpmkunit/src/fpmkunit.pp @@ -1059,8 +1059,12 @@ Type FOptions: TStrings; FCPU: TCPU; FOS: TOS; + FSourceCPU: TCPU; + FSourceOS: TOS; FMode : TCompilerMode; + FCompilerDate : String; FCompilerVersion : String; + FFullCompilerVersion : String; FPrefix: String; FBaseInstallDir, FUnitInstallDir, @@ -1134,7 +1138,11 @@ Type Property Target : String Read FTarget Write SetTarget; Property OS : TOS Read FOS Write SetOS; Property CPU : TCPU Read FCPU Write SetCPU; + Property SourceOS : TOS Read FSourceOS; + Property SourceCPU : TCPU Read FSourceCPU; Property CompilerVersion : String read FCompilerVersion; + Property CompilerDate : String read FCompilerDate; + Property FullCompilerVersion : String read FFullCompilerVersion; Property ExplicitOSNone: Boolean read FExplicitOSNone Write FExplicitOSNone; Property BuildString : String read GetBuildString; Property BuildOS : TOS read GetBuildOS; @@ -1774,6 +1782,7 @@ ResourceString SWarnExtCommandNotFound = 'Warning: External command "%s" not found but "%s" is older then "%s"'; SWarnDuplicatePackage = 'Warning: Package %s is already added. Using the existing package'; SWarngccNotFound = 'Could not find libgcc'; + SWarncrossgccNotFound = 'Could not find libgcc for cross-configuration'; SWarngcclibpath = 'Warning: Unable to determine the libgcc path.'; SWarnNoFCLProcessSupport= 'No FCL-Process support'; SWarnRetryRemDirectory = 'Failed to remove directory "%s". Retry after a short delay'; @@ -2838,6 +2847,12 @@ end; function GetDefaultLibGCCDir(CPU : TCPU;OS: TOS; var ErrorMessage: string): string; +var + CrossPrefix: string; + UseBinutilsPrefix: boolean; + SourceOS : TOS; + SourceCPU : TCPU; + function Get4thWord(const AString: string): string; var p: pchar; spacecount: integer; @@ -2874,7 +2889,7 @@ function GetDefaultLibGCCDir(CPU : TCPU;OS: TOS; var ErrorMessage: string): stri GccExecutable: string; begin result := ''; - GccExecutable := ExeSearch(AddProgramExtension('gcc', OS),Sysutils.GetEnvironmentVariable('PATH')); + GccExecutable := ExeSearch(AddProgramExtension(CrossPrefix+'gcc', OS),Sysutils.GetEnvironmentVariable('PATH')); if FileExists(GccExecutable) then begin {$ifdef HAS_UNIT_PROCESS} @@ -2894,6 +2909,8 @@ function GetDefaultLibGCCDir(CPU : TCPU;OS: TOS; var ErrorMessage: string): stri ErrorMessage := SWarnNoFCLProcessSupport; {$endif HAS_UNIT_PROCESS} end + else if UseBinutilsPrefix then + ErrorMessage := SWarncrossgccNotFound else ErrorMessage := SWarngccNotFound; end; @@ -2901,10 +2918,53 @@ function GetDefaultLibGCCDir(CPU : TCPU;OS: TOS; var ErrorMessage: string): stri begin result := ''; ErrorMessage:=''; + if assigned(Defaults) then + begin + SourceOS:=Defaults.SourceOS; + SourceCPU:=Defaults.SourceCPU; + end + else + begin + SourceOS:=StringToOS({$I %FPCTARGETOS%}); + SourceCPU:=StringToCPU({$I %FPCTARGETCPU%}); + end; + + if (SourceOS<>OS) then + UseBinutilsPrefix:=true; + if (SourceCPU<>CPU) then + begin + { we need to accept 32<->64 conversion } + { expect for OpenBSD which does not allow this } + if not( + ((SourceCPU=aarch64) and (CPU=arm)) or + ((SourceCPU=powerpc64) and (CPU=powerpc)) or + ((SourceCPU=x86_64) and (CPU=i386)) or + ((SourceCPU=riscv64) and (CPU=riscv32)) or + ((SourceCPU=sparc64) and (CPU=sparc)) or + ((CPU=aarch64) and (SourceCPU=arm)) or + ((CPU=powerpc64) and (SourceCPU=powerpc)) or + ((CPU=x86_64) and (SourceCPU=i386)) or + ((CPU=riscv64) and (SourceCPU=riscv32)) or + ((CPU=sparc64) and (SourceCPU=sparc)) + ) or (SourceOS=openbsd) then + UseBinutilsPrefix:=true; + end; + if not UseBinutilsPrefix then + CrossPrefix:='' + else if Sysutils.GetEnvironmentVariable('BINUTILSPREFIX')<>'' then + CrossPrefix:=Sysutils.GetEnvironmentVariable('BINUTILSPREFIX') + else + CrossPrefix:=CPUToString(CPU)+'-'+OSToString(OS)+'-'; if OS in [freebsd, openbsd, dragonfly] then - result := '/usr/local/lib' + begin + if CrossPrefix='' then + result := '/usr/local/lib' + end else if OS = netbsd then - result := '/usr/pkg/lib' + begin + if CrossPrefix='' then + result := '/usr/pkg/lib' + end else if OS = linux then case CPU of i386: result := GetGccDirArch('cpui386','-m32'); @@ -3323,9 +3383,8 @@ begin end; procedure TCompileWorkerThread.execute; -begin - while not Terminated do - begin + procedure RaiseMainEvent; + begin { Make sure all of our results are committed before we set (F)Done to true. While RTLeventSetEvent implies a barrier, once the main thread is notified it will walk over all threads and look for those that have Done=true -> it @@ -3334,6 +3393,12 @@ begin WriteBarrier; FDone:=true; RTLeventSetEvent(FNotifyMainThreadEvent); + end; +begin + if not Terminated then + RaiseMainEvent; + while not Terminated do + begin RTLeventWaitFor(FNotifyStartTask,500); if not FDone then begin @@ -3344,9 +3409,15 @@ begin try FBuildEngine.Compile(APackage); FCompilationOK:=true; + FBuildEngine.log(vlInfo,'Done compiling: '+APackage.Name); + RaiseMainEvent; except on E: Exception do - FErrorMessage := E.Message; + begin + FErrorMessage := 'Failed compiling: '+APackage.Name+': '+E.Message; + FBuildEngine.log(vlInfo,FErrorMessage); + RaiseMainEvent; + end; end; end; end; @@ -5019,6 +5090,27 @@ begin FCompilerVersion:={$I %FPCVERSION%}; {$endif HAS_UNIT_PROCESS} end; + if (FSourceOS=osNone) then + begin +{$ifdef HAS_UNIT_PROCESS} + // Detect compiler version/target from -i option + infosl:=TStringList.Create; + infosl.Delimiter:=' '; + infosl.DelimitedText:=GetCompilerInfo(GetCompiler,'-iDWSPSO', False, True); + if infosl.Count<>4 then + Raise EInstallerError.Create(SErrInvalidFPCInfo); + FCompilerDate:=infosl[0]; + FFullCompilerVersion:=infosl[1]; + FSourceCPU:=StringToCPU(infosl[2]); + FSourceOS:=StringToOS(infosl[3]); +{$else HAS_UNIT_PROCESS} + // Defaults taken from compiler used to build fpmake + FSourceCPU:=StringToCPU({$I %FPCTARGETCPU%}); + FSourceOS:=StringToOS({$I %FPCTARGETOS%}); + FFullCompilerVersion:={$I %FPCFULLVERSION%}; + FCompilerDate:={$I %FPCDATE%}; +{$endif HAS_UNIT_PROCESS} + end; end; diff --git a/avx512-0037785/packages/fv/src/views.pas b/avx512-0037785/packages/fv/src/views.pas index cd85455f0c..7a44ccec42 100644 --- a/avx512-0037785/packages/fv/src/views.pas +++ b/avx512-0037785/packages/fv/src/views.pas @@ -1905,7 +1905,8 @@ VAR S, D: Sw_Integer; Min, Max: TPoint; PROCEDURE GrowI (Var I: Sw_Integer); BEGIN If (GrowMode AND gfGrowRel = 0) Then Inc(I, D) - Else I := (I * S + (S - D) SHR 1) DIV (S - D); { Calc grow value } + Else If S = D then I := 1 + Else I := (I * S + (S - D) SHR 1) DIV (S - D); { Calc grow value } END; BEGIN diff --git a/avx512-0037785/packages/pasjpeg/examples/demo.lpi b/avx512-0037785/packages/pasjpeg/examples/demo.lpi new file mode 100644 index 0000000000..99fac0cd7f --- /dev/null +++ b/avx512-0037785/packages/pasjpeg/examples/demo.lpi @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="12"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + <UseDefaultCompilerOptions Value="True"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <Title Value="demo"/> + <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="demo.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Demo"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="demo"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../src"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="ECompilerAbort"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/avx512-0037785/packages/pasjpeg/examples/example.pas b/avx512-0037785/packages/pasjpeg/examples/example.pas index 5362912c8c..a4f052883b 100644 --- a/avx512-0037785/packages/pasjpeg/examples/example.pas +++ b/avx512-0037785/packages/pasjpeg/examples/example.pas @@ -1,3 +1,8 @@ +{$IFDEF FPC} +{$MODE DELPHI} +{$GOTO ON} +{$DEFINE DELPHI_STREAM} +{$ENDIF} Unit example; { This file illustrates how to use the IJG code as a subroutine library @@ -37,6 +42,10 @@ function read_JPEG_file (filename : string) : boolean; implementation +{$ifdef delphi_stream} + uses + Classes; +{$endif delphi_stream} { <setjmp.h> is used for the optional error recovery mechanism shown in the second part of the example. } @@ -93,7 +102,11 @@ var jerr : jpeg_error_mgr; { More stuff } +{$ifdef delphi_stream} + outfile : TFileStream; +{$else delphi_stream} outfile : FILE; { target file } +{$endif delphi_stream} row_pointer : array[0..0] of JSAMPROW ; { pointer to JSAMPLE row[s] } row_stride : int; { physical row width in image buffer } begin @@ -117,7 +130,9 @@ begin stdio stream. You can also write your own code to do something else. VERY IMPORTANT: use "b" option to fopen() if you are on a machine that requires it in order to write binary files. } - +{$ifdef delphi_stream} + outfile := TFileStream.Create(filename, fmCreate); +{$else delphi_stream} Assign(outfile, filename); {$push}{$I-} ReWrite(outfile, 1); @@ -127,6 +142,7 @@ begin WriteLn(output, 'can''t open ', filename); Halt(1); end; +{$endif delphi_stream} jpeg_stdio_dest(@cinfo, @outfile); { Step 3: set parameters for compression } @@ -179,7 +195,11 @@ begin jpeg_finish_compress(@cinfo); { After finish_compress, we can close the output file. } +{$ifdef delphi_stream} + outfile.Free; +{$else delphi_stream} system.close(outfile); +{$endif delphi_stream} { Step 7: release JPEG compression object } @@ -321,7 +341,11 @@ var jerr : my_error_mgr; { More stuff } - infile : FILE; { source file } +{$ifdef delphi_stream} + infile : TFileStream; +{$else delphi_stream} + infile : FILE; { target file } +{$endif delphi_stream} buffer : JSAMPARRAY; { Output row buffer } row_stride : int; { physical row width in output buffer } begin @@ -331,6 +355,9 @@ begin VERY IMPORTANT: use "b" option to fopen() if you are on a machine that requires it in order to read binary files. } +{$ifdef delphi_stream} + infile := TFileStream.Create(filename, fmOpenRead); +{$else delphi_stream} Assign(infile, filename); {$push}{$I-} Reset(infile, 1); @@ -341,6 +368,7 @@ begin read_JPEG_file := FALSE; exit; end; +{$endif delphi_stream} { Step 1: allocate and initialize JPEG decompression object } @@ -356,7 +384,11 @@ begin { Nomssi: if we get here, we are in trouble, because e.g. cinfo.mem is not guaranted to be NIL } jpeg_destroy_decompress(@cinfo); +{$ifdef delphi_stream} + infile.Free; +{$else delphi_stream} system.close(infile); +{$endif delphi_stream} read_JPEG_file := FALSE; exit; end; @@ -440,7 +472,11 @@ begin Here we postpone it until after no more JPEG errors are possible, so as to simplify the setjmp error logic above. (Actually, I don't think that jpeg_destroy can do an error exit, but why assume anything...) } +{$ifdef delphi_stream} + infile.Free; +{$else delphi_stream} system.close(infile); +{$endif delphi_stream} { At this point you may want to check to see whether any corrupt-data warnings occurred (test whether jerr.pub.num_warnings is nonzero). } diff --git a/avx512-0037785/packages/pastojs/src/fppas2js.pp b/avx512-0037785/packages/pastojs/src/fppas2js.pp index 7d5d6756a7..f60b74be61 100644 --- a/avx512-0037785/packages/pastojs/src/fppas2js.pp +++ b/avx512-0037785/packages/pastojs/src/fppas2js.pp @@ -506,6 +506,7 @@ const nDuplicateMessageIdXAtY = 4029; nDispatchRequiresX = 4030; nConstRefNotForXAsConst = 4031; + nSymbolCannotBeExportedFromALibrary = 4032; // resourcestring patterns of messages resourcestring sPasElementNotSupported = 'Pascal element not supported: %s'; @@ -539,6 +540,7 @@ resourcestring sDuplicateMessageIdXAtY = 'Duplicate message id "%s" at %s'; sDispatchRequiresX = 'Dispatch requires %s'; sConstRefNotForXAsConst = 'ConstRef not yet implemented for %s. Treating as Const'; + sSymbolCannotBeExportedFromALibrary = 'The symbol cannot be exported from a library'; const ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter @@ -606,6 +608,7 @@ type pbifnValEnum, pbifnFreeLocalVar, pbifnFreeVar, + pbifnLibraryMain, pbifnOverflowCheckInt, pbifnProcType_Create, pbifnProcType_CreateSafe, @@ -671,6 +674,7 @@ type pbivnImplCode, pbivnMessageInt, pbivnMessageStr, + pbivnLibrary, // library pbivnLocalModuleRef, pbivnLocalProcRef, pbivnLocalTypeRef, @@ -682,6 +686,7 @@ type pbivnPtrClass, pbivnPtrRecord, pbivnProcOk, + pbivnProgram, // program pbivnResourceStrings, pbivnResourceStringOrig, pbivnRTL, @@ -791,6 +796,7 @@ const 'valEnum', // pbifnValEnum rtl.valEnum 'freeLoc', // pbifnFreeLocalVar rtl.freeLoc 'free', // pbifnFreeVar rtl.free + '$main', // pbifnLibraryMain 'oc', // pbifnOverflowCheckInt rtl.oc 'createCallback', // pbifnProcType_Create rtl.createCallback 'createSafeCallback', // pbifnProcType_CreateSafe rtl.createSafeCallback @@ -855,6 +861,7 @@ const '$implcode', // pbivnImplCode '$msgint', // pbivnMessageInt '$msgstr', // pbivnMessageStr + 'library', // pbivnLibrary pas.library '$lm', // pbivnLocalModuleRef '$lp', // pbivnLocalProcRef '$lt', // pbivnLocalTypeRef @@ -866,6 +873,7 @@ const '$class', // pbivnPtrClass, ClassType '$record', // pbivnPtrRecord, hidden recordtype '$ok', // pbivnProcOk + 'program', // pbivnProgram pas.program '$resourcestrings', // pbivnResourceStrings 'org', // pbivnResourceStringOrig 'rtl', // pbivnRTL @@ -1538,6 +1546,7 @@ type Params: TParamsExpr); override; procedure FinishPropertyParamAccess(Params: TParamsExpr; Prop: TPasProperty ); override; + procedure FinishExportSymbol(El: TPasExportSymbol); override; procedure FindCreatorArrayOfConst(Args: TFPList; ErrorEl: TPasElement); function FindProc_ArrLitToArrayOfConst(ErrorEl: TPasElement): TPasFunction; virtual; function FindSystemExternalClassType(const aClassName, JSName: string; @@ -2071,7 +2080,7 @@ 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: TPasProgram; Src: TJSSourceElements; AContext: TConvertContext); virtual; + Procedure AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual; Procedure AddDelaySpecializeInit(El: TPasGenericType; Src: TJSSourceElements; AContext: TConvertContext); virtual; // enum and sets Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual; @@ -3945,6 +3954,7 @@ var begin Lines:=El.Tokens; if Lines=nil then exit; + // ToDo: resolve explicit references end; procedure TPas2JSResolver.ResolveNameExpr(El: TPasExpr; const aName: string; @@ -4880,6 +4890,41 @@ begin FindCreatorArrayOfConst(Args,Params); end; +procedure TPas2JSResolver.FinishExportSymbol(El: TPasExportSymbol); +var + ResolvedEl: TPasResolverResult; + DeclEl: TPasElement; + Proc: TPasProcedure; +begin + if El.Parent is TLibrarySection then + // ok + else + // everywhere else: not supported + RaiseMsg(20210106224720,nNotSupportedX,sNotSupportedX,['non library export'],El.ExportIndex); + if El.ExportIndex<>nil then + RaiseMsg(20210106223403,nNotSupportedX,sNotSupportedX,['export index'],El.ExportIndex); + + inherited FinishExportSymbol(El); + + ComputeElement(El,ResolvedEl,[]); + DeclEl:=ResolvedEl.IdentEl; + if DeclEl=nil then + RaiseMsg(20210106223620,nSymbolCannotBeExportedFromALibrary, + sSymbolCannotBeExportedFromALibrary,[],El) + else if DeclEl is TPasProcedure then + begin + Proc:=TPasProcedure(DeclEl); + if Proc.Parent is TPasSection then + // ok + else + RaiseMsg(20210106224436,nSymbolCannotBeExportedFromALibrary, + sSymbolCannotBeExportedFromALibrary,[],El); + end + else + RaiseMsg(20210106223621,nSymbolCannotBeExportedFromALibrary, + sSymbolCannotBeExportedFromALibrary,[],El); +end; + procedure TPas2JSResolver.FindCreatorArrayOfConst(Args: TFPList; ErrorEl: TPasElement); var @@ -8083,6 +8128,18 @@ Program: }; }); +Library: + rtl.module('library', + [<uses1>,<uses2>, ...], + function(){ + var $mod = this; + <librarysection> + this.$main=function(){ + <initialization> + }; + }); + export1 = pas.unit1.func1; + Unit without implementation: rtl.module('<unitname>', [<interface uses1>,<uses2>, ...], @@ -8136,6 +8193,7 @@ begin ModScope:=nil; OuterSrc:=TJSSourceElements(CreateElement(TJSSourceElements, El)); Result:=OuterSrc; + IntfContext:=nil; ok:=false; try // create 'rtl.module(...)' @@ -8145,7 +8203,7 @@ begin ArgArray := RegModuleCall.Args; RegModuleCall.Args:=ArgArray; - // add unitname parameter: unitname + // add module name parameter ModuleName:=TransformModuleName(El,false,AContext); ArgArray.Elements.AddElement.Expr:=CreateLiteralString(El,ModuleName); @@ -8183,95 +8241,88 @@ begin IntfContext:=TInterfaceSectionContext.Create(El,Src,AContext) else IntfContext:=TSectionContext.Create(El,Src,AContext); - try - // add "var $mod = this;" - IntfContext.ThisVar.Element:=El; - IntfContext.ThisVar.Kind:=cvkGlobal; - if El.CustomData is TPasModuleScope then - IntfContext.ScannerBoolSwitches:=TPasModuleScope(El.CustomData).BoolSwitches; - ModVarName:=GetBIName(pbivnModule); - IntfContext.AddLocalVar(ModVarName,El,cvkGlobal,false); - AddToSourceElements(Src,CreateVarStatement(ModVarName, - CreatePrimitiveDotExpr('this',El),El)); - - if (ModScope<>nil) then - RestoreImplJSLocals(ModScope,IntfContext); - - if (El is TPasProgram) then - begin // program - Prg:=TPasProgram(El); - if Assigned(Prg.ProgramSection) then - AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext)); - AddDelayedInits(Prg,Src,IntfContext); - CreateInitSection(Prg,Src,IntfContext); - end - else if El is TPasLibrary then - begin // library - Lib:=TPasLibrary(El); - if Assigned(Lib.LibrarySection) then - AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext)); - // ToDo AddDelayedInits(Lib,Src,IntfContext); - CreateInitSection(Lib,Src,IntfContext); - end - else - begin // unit - IntfSecCtx:=TInterfaceSectionContext(IntfContext); - if Assigned(El.ImplementationSection) then - begin - // add var $impl = $mod.$impl - ImplVarSt:=CreateVarStatement(GetBIName(pbivnImplementation), - CreateMemberExpression([ModVarName,GetBIName(pbivnImplementation)]),El); - AddToSourceElements(Src,ImplVarSt); - // register local var $impl - IntfSecCtx.AddLocalVar(GetBIName(pbivnImplementation),El.ImplementationSection,cvkGlobal,false); - end; - if Assigned(El.InterfaceSection) then - AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfSecCtx)); + // add "var $mod = this;" + IntfContext.ThisVar.Element:=El; + IntfContext.ThisVar.Kind:=cvkGlobal; + if El.CustomData is TPasModuleScope then + IntfContext.ScannerBoolSwitches:=TPasModuleScope(El.CustomData).BoolSwitches; + ModVarName:=GetBIName(pbivnModule); + IntfContext.AddLocalVar(ModVarName,El,cvkGlobal,false); + AddToSourceElements(Src,CreateVarStatement(ModVarName, + CreatePrimitiveDotExpr('this',El),El)); + + if (ModScope<>nil) then + RestoreImplJSLocals(ModScope,IntfContext); - ImplFunc:=CreateImplementationSection(El,IntfSecCtx); - // add $mod.$implcode = ImplFunc; - AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); - AssignSt.LHS:=CreateMemberExpression([ModVarName,GetBIName(pbivnImplCode)]); - AssignSt.Expr:=ImplFunc; - AddToSourceElements(Src,AssignSt); - - // append initialization section - CreateInitSection(El,Src,IntfSecCtx); + if (El is TPasProgram) then + begin // program + Prg:=TPasProgram(El); + if Assigned(Prg.ProgramSection) then + AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext)); + AddDelayedInits(Prg,Src,IntfContext); + CreateInitSection(Prg,Src,IntfContext); + end + else if El is TPasLibrary then + begin // library + Lib:=TPasLibrary(El); + if Assigned(Lib.LibrarySection) then + AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext)); + AddDelayedInits(Lib,Src,IntfContext); + CreateInitSection(Lib,Src,IntfContext); + // ToDo: append exports + end + else + begin // unit + IntfSecCtx:=TInterfaceSectionContext(IntfContext); + if Assigned(El.ImplementationSection) then + begin + // add var $impl = $mod.$impl + ImplVarSt:=CreateVarStatement(GetBIName(pbivnImplementation), + CreateMemberExpression([ModVarName,GetBIName(pbivnImplementation)]),El); + AddToSourceElements(Src,ImplVarSt); + // register local var $impl + IntfSecCtx.AddLocalVar(GetBIName(pbivnImplementation),El.ImplementationSection,cvkGlobal,false); + end; + if Assigned(El.InterfaceSection) then + AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfSecCtx)); + + ImplFunc:=CreateImplementationSection(El,IntfSecCtx); + // add $mod.$implcode = ImplFunc; + AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El)); + AssignSt.LHS:=CreateMemberExpression([ModVarName,GetBIName(pbivnImplCode)]); + AssignSt.Expr:=ImplFunc; + AddToSourceElements(Src,AssignSt); - if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count=0 then - begin - // empty implementation - - // remove unneeded $impl from interface - RemoveFromSourceElements(Src,ImplVarSt); - // remove unneeded $mod.$implcode = function(){} - RemoveFromSourceElements(Src,AssignSt); - HasImplUsesClause:=(El.ImplementationSection<>nil) - and (length(El.ImplementationSection.UsesClause)>0); - end - else - begin - HasImplUsesClause:=true; - end; + // append initialization section + CreateInitSection(El,Src,IntfSecCtx); - if HasImplUsesClause then - // add implementation uses list: [<implementation uses1>,<uses2>, ...] - ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext)); + if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count=0 then + begin + // empty implementation + // remove unneeded $impl from interface + RemoveFromSourceElements(Src,ImplVarSt); + // remove unneeded $mod.$implcode = function(){} + RemoveFromSourceElements(Src,AssignSt); + HasImplUsesClause:=(El.ImplementationSection<>nil) + and (length(El.ImplementationSection.UsesClause)>0); + end + else + begin + HasImplUsesClause:=true; end; - if (ModScope<>nil) and (coStoreImplJS in Options) then - StoreImplJSLocals(ModScope,IntfContext); - finally - IntfContext.Free; - end; + if HasImplUsesClause then + // add implementation uses list: [<implementation uses1>,<uses2>, ...] + ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext)); - // add implementation function - if ImplVarSt<>nil then - begin - end; + end; // end unit + + if (ModScope<>nil) and (coStoreImplJS in Options) then + StoreImplJSLocals(ModScope,IntfContext); ok:=true; finally + IntfContext.Free; if not ok then FreeAndNil(Result); end; @@ -13348,6 +13399,15 @@ begin Result:=Add; exit; end + else if bt in btAllJSInteger then + begin + // ord(integer) + Result:=CheckOrdConstant(aResolver,Param); + if Result<>nil then exit; + // ord(integer) -> integer + Result:=ConvertExpression(Param,AContext); + exit; + end else if bt=btContext then begin C:=ParamResolved.LoTypeEl.ClassType; @@ -15397,6 +15457,8 @@ begin end else if C=TPasAttributes then continue + else if C=TPasExportSymbol then + continue else RaiseNotSupported(P as TPasElement,AContext,20161024191434); Add(E,P); @@ -17148,11 +17210,21 @@ begin Scope:=nil; end; - IsMain:=(El is TPasProgram); - if IsMain then + if El.ClassType=TPasProgram then + begin + IsMain:=true; FunName:=GetBIName(pbifnProgramMain) + end + else if El.ClassType=TPasLibrary then + begin + IsMain:=true; + FunName:=GetBIName(pbifnLibraryMain) + end else + begin + IsMain:=false; FunName:=GetBIName(pbifnUnitInit); + end; NeedRTLCheckVersion:=IsMain and (coRTLVersionCheckMain in Options); RootContext:=AContext.GetRootContext as TRootContext; @@ -17489,6 +17561,7 @@ var L: TJSLiteral; AsmLines: TStrings; Line, Col, StartLine: integer; + Statements: TJSStatementList; begin if AContext=nil then ; AsmLines:=El.Tokens; @@ -17507,6 +17580,15 @@ begin L:=TJSLiteral.Create(Line+StartLine,Col,El.SourceFilename); L.Value.CustomValue:=TJSString(s); Result:=L; + if Pos(';',s)>0 then + begin + // multi statement JS + // for example "if e then asm a;b end;" + // -> if (e){ a;b } + Statements:=TJSStatementList.Create(L.Line,L.Column,L.Source); + Statements.A:=L; + Result:=Statements; + end; end; end; @@ -17680,7 +17762,7 @@ begin IntfSec.AddImplHeaderStatement(JS); end; -procedure TPasToJSConverter.AddDelayedInits(El: TPasProgram; +procedure TPasToJSConverter.AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); var aResolver: TPas2JSResolver; @@ -26397,13 +26479,7 @@ begin or (C=TPasClassDestructor) then AddGlobalClassMethod(FuncContext,TPasProcedure(P)) else - begin Methods.Add(P); - if (C=TPasConstructor) - or ((aResolver<>nil) and aResolver.IsClassMethod(P) - and not aResolver.MethodIsStatic(TPasProcedure(P))) then - IsComplex:=true; // needs $record - end; end else if C=TPasAttributes then else @@ -26617,8 +26693,10 @@ begin if Result<>'' then exit; end; - if El is TPasProgram then - Result:='program' + if El.ClassType=TPasProgram then + Result:=GetBIName(pbivnProgram) + else if El.ClassType=TPasLibrary then + Result:=GetBIName(pbivnLibrary) else begin Result:=''; diff --git a/avx512-0037785/packages/pastojs/src/pas2jsfiler.pp b/avx512-0037785/packages/pastojs/src/pas2jsfiler.pp index 3767d01d2c..4a28a96f78 100644 --- a/avx512-0037785/packages/pastojs/src/pas2jsfiler.pp +++ b/avx512-0037785/packages/pastojs/src/pas2jsfiler.pp @@ -609,6 +609,7 @@ type public Owner: TObject; end; + EPas2JsFilerErrorClass = class of EPas2JsFilerError; EPas2JsWriteError = class(EPas2JsFilerError); EPas2JsReadError = class(EPas2JsFilerError); @@ -665,6 +666,7 @@ type TPCUFiler = class private + FErrorClass: EPas2JsFilerErrorClass; FFileVersion: longint; FGUID: TGUID; FInitialFlags: TPCUInitialFlags; @@ -676,7 +678,7 @@ type function GetSourceFiles(Index: integer): TPCUSourceFile; protected FElementRefs: TAVLTree; // tree of TPCUFilerElementRef sorted for Element - procedure RaiseMsg(Id: int64; const Msg: string = ''); virtual; abstract; overload; + procedure RaiseMsg(Id: int64; const Msg: string = ''); virtual; overload; procedure RaiseMsg(Id: int64; El: TPasElement; const Msg: string = ''); overload; function GetDefaultMemberVisibility(El: TPasElement): TPasMemberVisibility; virtual; function GetDefaultPasScopeVisibilityContext(Scope: TPasScope): TPasElement; virtual; @@ -703,6 +705,7 @@ type property SourceFiles[Index: integer]: TPCUSourceFile read GetSourceFiles; property ElementRefs: TAVLTree read FElementRefs; property GUID: TGUID read FGUID write FGUID; + property ErrorClass: EPas2JsFilerErrorClass read FErrorClass write FErrorClass; end; { TPCUCustomWriter } @@ -711,6 +714,7 @@ type private FOnIsElementUsed: TPas2JSIsElementUsedEvent; public + constructor Create; override; procedure WritePCU(aResolver: TPas2JSResolver; aConverter: TPasToJSConverter; InitFlags: TPCUInitialFlags; aStream: TStream; Compressed: boolean); virtual; abstract; property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed; @@ -721,12 +725,15 @@ type TPCUCustomReader = class(TPCUFiler) private + FPCUFilename: string; FSourceFilename: string; public + constructor Create; override; procedure ReadPCU(aResolver: TPas2JSResolver; aStream: TStream); virtual; abstract; function ReadContinue: boolean; virtual; abstract; // true=finished function ReadCanContinue: boolean; virtual; // true=not finished and no pending used interface property SourceFilename: string read FSourceFilename write FSourceFilename; // default value for TPasElement.SourceFilename + property PCUFilename: string read FPCUFilename write FPCUFilename; // for nicer error messages end; TPCUReaderClass = class of TPCUCustomReader; @@ -768,7 +775,6 @@ type FBuiltInSymbolsArr: TJSONArray; protected FFirstNewExt, FLastNewExt: TPCUFilerElementRef; // not yet stored external references - procedure RaiseMsg(Id: int64; const Msg: string = ''); override; overload; procedure ResolvePendingElRefs(Ref: TPCUFilerElementRef); function CheckElScope(El: TPasElement; NotNilId: int64; ScopeClass: TPasScopeClass): TPasScope; virtual; procedure AddArrayFlag(Obj: TJSONObject; var Arr: TJSONArray; @@ -1239,6 +1245,7 @@ type procedure ReadPCU(aResolver: TPas2JSResolver; aStream: TStream); override; // sets property JSON, reads header and returns procedure ReadJSONHeader(aResolver: TPas2JSResolver; Obj: TJSONObject); virtual; function ReadContinue: boolean; override; // true=finished + function GetPCUExt: string; virtual; // without dot property FileVersion: longint read FFileVersion; property JSON: TJSONObject read FJSON; end; @@ -1857,6 +1864,14 @@ begin AddLine(Line); end; +{ TPCUCustomWriter } + +constructor TPCUCustomWriter.Create; +begin + inherited Create; + FErrorClass:=EPas2JsWriteError; +end; + { TPCUReaderPendingSpecialized } destructor TPCUReaderPendingSpecialized.Destroy; @@ -1877,6 +1892,12 @@ end; { TPCUCustomReader } +constructor TPCUCustomReader.Create; +begin + inherited Create; + FErrorClass:=EPas2JsReadError; +end; + function TPCUCustomReader.ReadCanContinue: boolean; var Module: TPasModule; @@ -1930,6 +1951,18 @@ begin Result:=TPCUSourceFile(FSourceFiles[Index]); end; +procedure TPCUFiler.RaiseMsg(Id: int64; const Msg: string); +var + E: EPas2JsFilerError; +begin + E:=ErrorClass.Create('['+IntToStr(Id)+'] '+Msg); + E.Owner:=Self; + {$IFDEF VerbosePCUFiler} + writeln(ClassName+'/TPCUFiler.RaiseMsg ',E.Message); + {$ENDIF} + raise E; +end; + procedure TPCUFiler.RaiseMsg(Id: int64; El: TPasElement; const Msg: string); var Path, s: String; @@ -2215,18 +2248,6 @@ begin end; end; -procedure TPCUWriter.RaiseMsg(Id: int64; const Msg: string); -var - E: EPas2JsWriteError; -begin - E:=EPas2JsWriteError.Create('['+IntToStr(Id)+'] '+Msg); - E.Owner:=Self; - {$IFDEF VerbosePCUFiler} - writeln('TPCUWriter.RaiseMsg ',E.Message); - {$ENDIF} - raise E; -end; - function TPCUWriter.CheckElScope(El: TPasElement; NotNilId: int64; ScopeClass: TPasScopeClass): TPasScope; var @@ -5781,12 +5802,16 @@ end; procedure TPCUReader.RaiseMsg(Id: int64; const Msg: string); var - E: EPas2JsReadError; + E: EPas2JsFilerError; + s: String; begin - E:=EPas2JsReadError.Create('['+IntToStr(Id)+'] '+Msg); + s:='['+IntToStr(Id)+'] '+Msg; + if PCUFilename<>'' then + s:=s+' file: '+PCUFilename; + E:=ErrorClass.Create(s); E.Owner:=Self; {$IFDEF VerbosePCUFiler} - writeln('TPCUReader.RaiseMsg ',E.Message); + writeln(ClassName+'/TPCUReader.RaiseMsg ',E.Message); {$ENDIF} raise E; end; @@ -6317,9 +6342,9 @@ begin writeln('TPCUReader.ReadHeaderVersion ',FFileVersion); {$ENDIF} if FFileVersion<1 then - RaiseMsg(20180130201801,'invalid PCU file version'); + RaiseMsg(20180130201801,'invalid file version'); if FFileVersion>PCUVersion then - RaiseMsg(20180130201822,'pcu file was created by a newer compiler.'); + RaiseMsg(20180130201822,'file was created by a newer compiler.'); end; procedure TPCUReader.ReadGUID(Obj: TJSONObject); @@ -10135,6 +10160,15 @@ begin {$ENDIF} end; +function TPCUReader.GetPCUExt: string; +begin + Result:=ExtractFileExt(PCUFilename); + if Result='' then + Result:='pcu' + else + System.Delete(Result,1,1); // remove leading dot +end; + { TPas2JSPrecompileFormats } function TPas2JSPrecompileFormats.GetItems(Index: integer diff --git a/avx512-0037785/packages/pastojs/src/pas2jspcucompiler.pp b/avx512-0037785/packages/pastojs/src/pas2jspcucompiler.pp index 5baf59da7a..ec9eedc432 100644 --- a/avx512-0037785/packages/pastojs/src/pas2jspcucompiler.pp +++ b/avx512-0037785/packages/pastojs/src/pas2jspcucompiler.pp @@ -187,6 +187,7 @@ begin RaiseInternalError(20180312142954,''); FPCUReader:=FPCUFormat.ReaderClass.Create; FPCUReader.SourceFilename:=ExtractFileName(MyFile.PCUFilename); + FPCUReader.PCUFilename:=MyFile.PCUFilename; if MyFile.ShowDebug then MyFile.Log.LogMsg(nParsingFile,[QuoteStr(MyFile.PCUFilename)]); diff --git a/avx512-0037785/packages/pastojs/tests/tcmodules.pas b/avx512-0037785/packages/pastojs/tests/tcmodules.pas index 1ab920c33a..ca46edd38b 100644 --- a/avx512-0037785/packages/pastojs/tests/tcmodules.pas +++ b/avx512-0037785/packages/pastojs/tests/tcmodules.pas @@ -125,6 +125,7 @@ type FModules: TObjectList;// list of TTestEnginePasResolver FParser: TTestPasParser; FPasProgram: TPasProgram; + FPasLibrary: TPasLibrary; FHintMsgs: TObjectList; // list of TTestHintMessage FHintMsgsGood: TFPList; // list of TTestHintMessage marked as expected FJSRegModuleCall: TJSCallExpression; @@ -157,6 +158,7 @@ type procedure ParseModuleQueue; virtual; procedure ParseModule; virtual; procedure ParseProgram; virtual; + procedure ParseLibrary; virtual; procedure ParseUnit; virtual; protected function FindModuleWithFilename(aFilename: string): TTestEnginePasResolver; virtual; @@ -166,9 +168,11 @@ type ImplementationSrc: string): TTestEnginePasResolver; virtual; procedure AddSystemUnit(Parts: TSystemUnitParts = []); virtual; procedure StartProgram(NeedSystemUnit: boolean; SystemUnitParts: TSystemUnitParts = []); virtual; + procedure StartLibrary(NeedSystemUnit: boolean; SystemUnitParts: TSystemUnitParts = []); virtual; procedure StartUnit(NeedSystemUnit: boolean; SystemUnitParts: TSystemUnitParts = []); virtual; procedure ConvertModule; virtual; procedure ConvertProgram; virtual; + procedure ConvertLibrary; virtual; procedure ConvertUnit; virtual; function ConvertJSModuleToString(El: TJSElement): string; virtual; procedure CheckDottedIdentifier(Msg: string; El: TJSElement; DottedName: string); @@ -196,6 +200,7 @@ type function GetResolver(const Filename: string): TTestEnginePasResolver; function GetDefaultNamespace: string; property PasProgram: TPasProgram Read FPasProgram; + property PasLibrary: TPasLibrary Read FPasLibrary; property Resolvers[Index: integer]: TTestEnginePasResolver read GetResolvers; property ResolverCount: integer read GetResolverCount; property Engine: TTestEnginePasResolver read FEngine; @@ -332,6 +337,7 @@ type Procedure TestProc_External; Procedure TestProc_ExternalOtherUnit; Procedure TestProc_Asm; + Procedure TestProc_AsmSubBlock; Procedure TestProc_Assembler; Procedure TestProc_VarParam; Procedure TestProc_VarParamString; @@ -383,6 +389,7 @@ type Procedure TestSet_Property; Procedure TestSet_EnumConst; Procedure TestSet_IntConst; + Procedure TestSet_IntRange; Procedure TestSet_AnonymousEnumType; Procedure TestSet_AnonymousEnumTypeChar; // ToDo Procedure TestSet_ConstEnum; @@ -894,6 +901,12 @@ type Procedure TestAsync_Inherited; Procedure TestAsync_ClassInterface; Procedure TestAsync_ClassInterface_AsyncMissmatchFail; + + // Library + Procedure TestLibrary_Empty; + Procedure TestLibrary_ExportFunc; // ToDo + // ToDo: test delayed specialization init + // ToDO: analyzer end; function LinesToStr(Args: array of const): string; @@ -1587,6 +1600,22 @@ begin FFirstPasStatement:=TPasImplBlock(PasProgram.InitializationSection.Elements[0]); end; +procedure TCustomTestModule.ParseLibrary; +var + Init: TInitializationSection; +begin + if SkipTests then exit; + ParseModule; + if SkipTests then exit; + AssertEquals('Has library',TPasLibrary,Module.ClassType); + FPasLibrary:=TPasLibrary(Module); + AssertNotNull('Has library section',PasLibrary.LibrarySection); + Init:=PasLibrary.InitializationSection; + if (Init<>nil) and (Init.Elements.Count>0) then + if TObject(Init.Elements[0]) is TPasImplBlock then + FFirstPasStatement:=TPasImplBlock(PasLibrary.InitializationSection.Elements[0]); +end; + procedure TCustomTestModule.ParseUnit; begin if SkipTests then exit; @@ -1869,6 +1898,17 @@ begin Add(''); end; +procedure TCustomTestModule.StartLibrary(NeedSystemUnit: boolean; + SystemUnitParts: TSystemUnitParts); +begin + if NeedSystemUnit then + AddSystemUnit(SystemUnitParts) + else + Parser.ImplicitUses.Clear; + Add('library '+ExtractFileUnitName(Filename)+';'); + Add(''); +end; + procedure TCustomTestModule.StartUnit(NeedSystemUnit: boolean; SystemUnitParts: TSystemUnitParts); begin @@ -1974,6 +2014,8 @@ begin AssertEquals('module name param is string',ord(jstString),ord(ModuleNameExpr.Value.ValueType)); if Module is TPasProgram then AssertEquals('module name','program',String(ModuleNameExpr.Value.AsString)) + else if Module is TPasLibrary then + AssertEquals('module name','library',String(ModuleNameExpr.Value.AsString)) else AssertEquals('module name',Module.Name,String(ModuleNameExpr.Value.AsString)); @@ -1990,7 +2032,7 @@ begin CheckFunctionParam('module intf-function',Arg,FJSModuleSrc); // search for $mod.$init or $mod.$main - the last statement - if Module is TPasProgram then + if (Module is TPasProgram) or (Module is TPasLibrary) then begin InitName:='$main'; AssertEquals('$mod.'+InitName+' function 1',true,JSModuleSrc.Statements.Count>0); @@ -2009,7 +2051,7 @@ begin InitFunction:=InitAssign.Expr as TJSFunctionDeclarationStatement; FJSInitBody:=InitFunction.AFunction.Body as TJSFunctionBody; end - else if Module is TPasProgram then + else if (Module is TPasProgram) or (Module is TPasLibrary) then CheckDottedIdentifier('init function',InitAssign.LHS,'$mod.'+InitName); end; end; @@ -2028,6 +2070,13 @@ begin ConvertModule; end; +procedure TCustomTestModule.ConvertLibrary; +begin + Add('end.'); + ParseLibrary; + ConvertModule; +end; + procedure TCustomTestModule.ConvertUnit; begin Add('end.'); @@ -2089,7 +2138,7 @@ begin // program main or unit initialization if (Module is TPasProgram) or (Trim(InitStatements)<>'') then begin - if Module is TPasProgram then + if (Module is TPasProgram) or (Module is TPasLibrary) then InitName:='$main' else InitName:='$init'; @@ -4092,6 +4141,65 @@ begin ])); end; +procedure TTestModule.TestProc_AsmSubBlock; +begin + StartProgram(true,[supTObject]); + Add([ + '{$mode delphi}', + 'type', + ' TBird = class end;', + 'procedure Run(w: word);', + 'begin;', + ' if true then asm console.log(); end;', + ' if w>3 then asm', + ' var a = w+1;', + ' w = a+3;', + ' end;', + ' while (w>7) do asm', + ' w+=3; w*=2;', + ' end;', + ' try', + ' except', + ' on E: TBird do', + ' asm console.log(E); end;', + ' on E: TObject do', + ' asm var i=3; i--; end;', + ' else asm Fly; High; end;', + ' end;', + 'end;', + 'begin']); + ConvertProgram; + CheckSource('TestProc_AsmSubBlock', + LinesToStr([ // statements + 'rtl.createClass(this, "TBird", pas.system.TObject, function () {', + '});', + 'this.Run = function (w) {', + ' if (true) console.log();', + ' if (w > 3) {', + ' var a = w+1;', + ' w = a+3;', + ' };', + ' while (w > 7) {', + ' w+=3; w*=2;', + ' };', + ' try {} catch ($e) {', + ' if ($mod.TBird.isPrototypeOf($e)) {', + ' var E = $e;', + ' console.log(E);', + ' } else if (pas.system.TObject.isPrototypeOf($e)) {', + ' var E = $e;', + ' var i=3; i--;', + ' } else {', + ' Fly; High;', + ' }', + ' };', + '};', + '']), + LinesToStr([ + '' + ])); +end; + procedure TTestModule.TestProc_Assembler; begin StartProgram(false); @@ -6313,6 +6421,44 @@ begin ''])); end; +procedure TTestModule.TestSet_IntRange; +begin + StartProgram(false); + Add([ + 'type', + ' TRange = 1..3;', + ' TEnums = set of TRange;', + 'const', + ' Orange = 2;', + 'var', + ' Enum: byte;', + ' Enums: TEnums;', + 'begin', + ' Enums:=[];', + ' Enums:=[1];', + ' Enums:=[2..3];', + ' Include(enums,orange);', + ' Exclude(enums,orange);', + ' if orange in enums then;', + ' if orange in [orange,1] then;']); + ConvertProgram; + CheckSource('TestSet_IntRange', + LinesToStr([ // statements + 'this.Orange = 2;', + 'this.Enum = 0;', + 'this.Enums = {};', + '']), + LinesToStr([ + '$mod.Enums = {};', + '$mod.Enums = rtl.createSet(1);', + '$mod.Enums = rtl.createSet(null, 2, 3);', + '$mod.Enums = rtl.includeSet($mod.Enums, 2);', + '$mod.Enums = rtl.excludeSet($mod.Enums, 2);', + 'if (2 in $mod.Enums) ;', + 'if (2 in rtl.createSet(2, 1)) ;', + ''])); +end; + procedure TTestModule.TestSet_AnonymousEnumType; begin StartProgram(false); @@ -7075,7 +7221,9 @@ begin 'begin', ' i:=i2;', ' i:=default(TMyInt);', - ' if i=i2 then ;']); + ' if i=i2 then ;', + ' i:=ord(i2);', + '']); ConvertProgram; CheckSource('TestIntegerRange', LinesToStr([ @@ -7096,6 +7244,7 @@ begin '$mod.i = $mod.i2;', '$mod.i = -1;', 'if ($mod.i === $mod.i2) ;', + '$mod.i = $mod.i2;', ''])); end; @@ -7210,6 +7359,7 @@ begin ' i:=system.high(i);', ' i:=system.pred(i);', ' i:=system.succ(i);', + ' i:=system.ord(i);', '']); ConvertProgram; CheckResolverUnexpectedHints; @@ -7226,6 +7376,7 @@ begin '$mod.i = 255;', '$mod.i = $mod.i - 1;', '$mod.i = $mod.i + 1;', + '$mod.i = $mod.i;', ''])); end; @@ -12292,12 +12443,20 @@ begin 'type', ' TPoint = record', ' x,y: longint;', + ' class procedure Run(w: longint = 13); static;', ' constructor Create(ax: longint; ay: longint = -1);', ' end;', + 'class procedure tpoint.run(w: longint);', + 'begin', + ' run;', + ' run();', + 'end;', 'constructor tpoint.create(ax,ay: longint);', 'begin', ' x:=ax;', ' self.y:=ay;', + ' run;', + ' run(ax);', 'end;', 'var r: TPoint;', 'begin', @@ -12320,12 +12479,18 @@ begin ' this.y = s.y;', ' return this;', ' };', + ' this.Run = function (w) {', + ' $mod.TPoint.Run(13);', + ' $mod.TPoint.Run(13);', + ' };', ' this.Create = function (ax, ay) {', ' this.x = ax;', ' this.y = ay;', + ' this.Run(13);', + ' this.Run(ax);', ' return this;', ' };', - '}, true);', + '});', 'this.r = this.TPoint.$new();', '']), LinesToStr([ // $mod.$main @@ -23241,7 +23406,7 @@ begin ' $mod.THelper.$new("NewHlp", [3]);', ' return this;', ' };', - '}, true);', + '});', 'rtl.createHelper(this, "THelper", null, function () {', ' this.NewHlp = function (w) {', ' this.Create(2);', @@ -33110,6 +33275,42 @@ begin ConvertProgram; end; +procedure TTestModule.TestLibrary_Empty; +begin + StartLibrary(false); + Add([ + '']); + ConvertLibrary; + CheckSource('TestLibrary_Empty', + LinesToStr([ // statements + '']), + LinesToStr([ + ''])); + CheckResolverUnexpectedHints(); +end; + +procedure TTestModule.TestLibrary_ExportFunc; +begin + exit; + + StartLibrary(false); + Add([ + 'procedure Run(w: word);', + 'begin', + 'end;', + 'exports', + ' Run,', + ' run name ''Foo'';', + '']); + ConvertLibrary; + CheckSource('TestLibrary_ExportFunc', + LinesToStr([ // statements + '']), + LinesToStr([ + ''])); + CheckResolverUnexpectedHints(); +end; + Initialization RegisterTests([TTestModule]); end. diff --git a/avx512-0037785/packages/rtl-extra/fpmake.pp b/avx512-0037785/packages/rtl-extra/fpmake.pp index 1830dd99db..0421a0eb8a 100644 --- a/avx512-0037785/packages/rtl-extra/fpmake.pp +++ b/avx512-0037785/packages/rtl-extra/fpmake.pp @@ -27,8 +27,6 @@ Const WinsockOSes = [win32,win64,wince,os2,emx,netware,netwlibc]; WinSock2OSes = [win32,win64,wince]; SocketsOSes = UnixLikes+AllAmigaLikeOSes+[netware,netwlibc,os2,emx,wince,win32,win64]; - Socksyscall = [beos,freebsd,haiku,linux,netbsd,openbsd,dragonfly]; - Socklibc = unixlikes-socksyscall; gpmOSes = [Linux,Android]; AllTargetsextra = ObjectsOSes + UComplexOSes + MatrixOSes+ SerialOSes +PrinterOSes+SocketsOSes+gpmOSes; @@ -36,6 +34,7 @@ Const Var P : TPackage; T : TTarget; + Socksyscall, Socklibc : set of Tos; begin With Installer do @@ -51,6 +50,15 @@ begin if Defaults.CPU=jvm then P.OSes := P.OSes - [java,android]; + Socksyscall := [beos,freebsd,haiku,linux,netbsd,dragonfly]; + Socklibc := unixlikes-socksyscall; +{$ifdef FPC_USE_SYSCALL} + if Defaults.OS=openbsd then + begin + system.include(Socksyscall,openbsd); + system.exclude(Socklibc,openbsd); + end; +{$endif} P.Email := ''; P.Description := 'Rtl-extra, RTL not needed for bootstrapping'; P.NeedLibC:= false; diff --git a/avx512-0037785/packages/rtl-extra/src/bsd/osdefs.inc b/avx512-0037785/packages/rtl-extra/src/bsd/osdefs.inc index 006f83e4b7..11dac66888 100644 --- a/avx512-0037785/packages/rtl-extra/src/bsd/osdefs.inc +++ b/avx512-0037785/packages/rtl-extra/src/bsd/osdefs.inc @@ -27,4 +27,9 @@ {$ifdef darwin} {$define FPC_USE_LIBC} {$endif} +{$ifdef openbsd} + {$ifndef FPC_USE_SYSCALL} + {$define FPC_USE_LIBC} + {$endif} +{$endif} diff --git a/avx512-0037785/packages/rtl-objpas/src/inc/dateutil.inc b/avx512-0037785/packages/rtl-objpas/src/inc/dateutil.inc index 212775196e..1269f3a040 100644 --- a/avx512-0037785/packages/rtl-objpas/src/inc/dateutil.inc +++ b/avx512-0037785/packages/rtl-objpas/src/inc/dateutil.inc @@ -1885,7 +1885,7 @@ end; function TryEncodeTimeInterval(Hour, Min, Sec, MSec: word; out Time: TDateTime): boolean; begin - Result:= (Min<60) and (Sec<60) and (MSec<1000); + Result:= (Min<60) and (Sec<60) and (MSec<=1000); If Result then Time:=TDateTime(cardinal(Hour)*3600000+cardinal(Min)*60000+cardinal(Sec)*1000+MSec)/MSecsPerDay; end; diff --git a/avx512-0037785/packages/rtl-objpas/src/inc/variants.pp b/avx512-0037785/packages/rtl-objpas/src/inc/variants.pp index 4682f3bfae..7e306f6aca 100644 --- a/avx512-0037785/packages/rtl-objpas/src/inc/variants.pp +++ b/avx512-0037785/packages/rtl-objpas/src/inc/variants.pp @@ -2351,10 +2351,14 @@ begin end; procedure DoVarCast(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt); +var + Handler: TCustomVariantType; begin with aSource do if vType = aVarType then DoVarCopy(aDest, aSource) + else if FindCustomVariantType(vType, Handler) then + Handler.CastTo(aDest, aSource, aVarType) else begin if (vType = varNull) and NullStrictConvert then VarCastError(varNull, aVarType); diff --git a/avx512-0037785/rtl/amiga/powerpc/execf.inc b/avx512-0037785/rtl/amiga/powerpc/execf.inc index 7aecd3c608..b745f18488 100644 --- a/avx512-0037785/rtl/amiga/powerpc/execf.inc +++ b/avx512-0037785/rtl/amiga/powerpc/execf.inc @@ -35,6 +35,10 @@ function SetSignal(newSignals: longword; signalMask: longword): longword; syscal procedure AddPort(port: PMsgPort); syscall IExec 300; +function CreateMsgPort(): PMsgPort; syscall IExec 308; + +procedure DeleteMsgPort(Port: PMsgPort); syscall IExec 316; + function GetMsg(port: PMsgPort): PMessage; syscall IExec 324; procedure PutMsg(port: PMsgPort; message: PMessage); syscall IExec 328; procedure RemPort(port: PMsgPort); syscall IExec 332; @@ -58,6 +62,8 @@ procedure DropInterface(_interface: POS4Interface); syscall IExec 456; function OpenDevice(devName: PChar; unitNumber: longword;ioRequest: PIORequest; flags: longword): longint; syscall IExec 504; function CloseDevice(ioRequest: PIORequest): Pointer; syscall IExec 508; +function CreateIORequest(const IOReplyPort: PMsgPort; Size: LongWord): PIORequest; syscall IExec 512; +procedure DeleteIORequest(IORequest: PIORequest); syscall IExec 516; function DoIO(ioRequest: PIORequest): shortint; syscall IExec 528; diff --git a/avx512-0037785/rtl/i386/cpu.pp b/avx512-0037785/rtl/i386/cpu.pp index 7ef4af7b53..0ba4844035 100644 --- a/avx512-0037785/rtl/i386/cpu.pp +++ b/avx512-0037785/rtl/i386/cpu.pp @@ -70,22 +70,32 @@ unit cpu; function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; begin {$if FPC_FULLVERSION >= 30101} -{$ifndef FPC_PIC} +{$ifndef FPC_PIC} if _RTMSupport then begin asm - .Lretry: +{$ifdef USE_REAL_INSTRUCTIONS} + .Lretry: xbegin .Lretry +{$else} +{ 3d: c7 f8 fa ff ff ff xbegin } + .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff +{$endif} end; Result:=Target; if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then Target:=NewValue; asm +{$ifdef USE_REAL_INSTRUCTIONS} xend +{$else} + { 8a: 0f 01 d5 xend } + .byte 0x0f, 0x01, 0xd5 +{$endif} end; end else -{$endif FPC_PIC} +{$endif FPC_PIC} {$endif FPC_FULLVERSION >= 30101} RunError(217); end; @@ -119,7 +129,11 @@ unit cpu; function cr0 : longint;assembler; asm +{$ifdef USE_REAL_INSTRUCTIONS} + mov eax,cr0 +{$else} DB 0Fh,20h,0C0h +{$endif} { mov eax,cr0 special registers are not allowed in the assembler parsers } @@ -138,8 +152,12 @@ unit cpu; function XGETBV(i : dword) : int64;assembler; asm movl %eax,%ecx +{$ifdef USE_REAL_INSTRUCTIONS} + xgetbv +{$else} // older FPCs don't know the xgetbv opcode .byte 0x0f,0x01,0xd0 +{$endif} end; diff --git a/avx512-0037785/rtl/linux/i386/si_prc.inc b/avx512-0037785/rtl/linux/i386/si_prc.inc index ae0531dd9e..1639445a70 100644 --- a/avx512-0037785/rtl/linux/i386/si_prc.inc +++ b/avx512-0037785/rtl/linux/i386/si_prc.inc @@ -45,7 +45,9 @@ var procedure fpc_geteipasebxlocal; [external name 'fpc_geteipasebx']; {$endif} +{$ifndef FPC_USE_LIBC} procedure InitTLS; [external name 'FPC_INITTLS']; +{$endif} procedure _FPC_proc_start; assembler; nostackframe; public name '_start'; asm @@ -95,9 +97,9 @@ asm movl %esp,initialstkptr {$endif FPC_PIC} -{$if FPC_FULLVERSION>30200} +{$if (FPC_FULLVERSION>30200) and not defined(FPC_USE_LIBC)} call InitTLS -{$endif FPC_FULLVERSION>30200} +{$endif FPC_FULLVERSION>30200 and not FPC_USE_LIBC} xorl %ebp,%ebp call PASCALMAIN diff --git a/avx512-0037785/rtl/linux/linux.pp b/avx512-0037785/rtl/linux/linux.pp index 7a31fdf8f1..4c661a81df 100644 --- a/avx512-0037785/rtl/linux/linux.pp +++ b/avx512-0037785/rtl/linux/linux.pp @@ -20,7 +20,7 @@ unit Linux; {$i osdefs.inc} {$packrecords c} -{$ifdef FPC_USE_LIBC} +{$ifdef FPC_USE_LIBC} {$linklib rt} // for clock* functions {$endif} @@ -40,7 +40,7 @@ type __s32 = Longint; __u64 = QWord; __s64 = Int64; - + type TSysInfo = record uptime: clong; //* Seconds since boot */ @@ -483,8 +483,8 @@ Type function clock_getres(clk_id : clockid_t; res : ptimespec) : cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'clock_getres'; {$ENDIF} function clock_gettime(clk_id : clockid_t; tp: ptimespec) : cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'clock_gettime'; {$ENDIF} function clock_settime(clk_id : clockid_t; tp : ptimespec) : cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'clock_settime'; {$ENDIF} -function setregid(rgid,egid : uid_t): cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'setregid'; {$ENDIF} -function setreuid(ruid,euid : uid_t): cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'setreuid'; {$ENDIF} +function setregid(rgid,egid : uid_t): cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'setregid'; {$ENDIF} +function setreuid(ruid,euid : uid_t): cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'setreuid'; {$ENDIF} Const STATX_TYPE = $00000001; @@ -517,7 +517,7 @@ Type end; pstatx_timestamp = ^statx_timestamp; - statx = record + tstatx = record stx_mask : __u32; stx_blksize : __u32; stx_attributes : __u64; @@ -540,9 +540,25 @@ Type stx_dev_minor : __u32; __spare2 : array[0..13] of __u64; end; - pstatx = ^statx; + pstatx = ^tstatx; + + function statx(dfd: cint; filename: pchar; flags,mask: cuint; var buf: tstatx):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'statx'; {$ENDIF} + +Type + kernel_time64_t = clonglong; - function Fpstatx(dfd: cint; filename: pchar; flags,mask: cuint; var buf: statx):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'statx'; {$ENDIF} + kernel_timespec = record + tv_sec : kernel_time64_t; + tv_nsec : clonglong; + end; + pkernel_timespec = ^kernel_timespec; + + tkernel_timespecs = array[0..1] of kernel_timespec; + +{$ifndef android} +Function utimensat(dfd: cint; path:pchar;const times:tkernel_timespecs;flags:cint):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'utimensat'; {$ENDIF} +Function futimens(fd: cint; const times:tkernel_timespecs):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'futimens'; {$ENDIF} +{$endif android} implementation @@ -847,18 +863,60 @@ function setregid(rgid,egid : uid_t): cint; begin setregid:=do_syscall(syscall_nr_setregid,rgid,egid); end; - + function setreuid(ruid,euid : uid_t): cint; begin setreuid:=do_syscall(syscall_nr_setreuid,ruid,euid); end; -function Fpstatx(dfd: cint; filename: pchar; flags,mask: cuint; var buf: statx):cint; +function statx(dfd: cint; filename: pchar; flags,mask: cuint; var buf: tstatx):cint; begin - Fpstatx:=do_syscall(syscall_nr_statx,TSysParam(dfd),TSysParam(filename),TSysParam(flags),TSysParam(mask),TSysParam(@buf)); + statx:=do_syscall(syscall_nr_statx,TSysParam(dfd),TSysParam(filename),TSysParam(flags),TSysParam(mask),TSysParam(@buf)); end; -{$endif} + +{$ifndef android} +Function utimensat(dfd: cint; path:pchar;const times:tkernel_timespecs;flags:cint):cint; +var + tsa: Array[0..1] of timespec; +begin +{$if sizeof(clong)<=4} + utimensat:=do_syscall(syscall_nr_utimensat_time64,dfd,TSysParam(path),TSysParam(@times),0); + if (utimensat>=0) or (fpgeterrno<>ESysENOSYS) then + exit; + { try 32 bit fall back } + tsa[0].tv_sec := times[0].tv_sec; + tsa[0].tv_nsec := times[0].tv_nsec; + tsa[1].tv_sec := times[1].tv_sec; + tsa[1].tv_nsec := times[1].tv_nsec; + utimensat:=do_syscall(syscall_nr_utimensat,dfd,TSysParam(path),TSysParam(@tsa),0); +{$else sizeof(clong)<=4} + utimensat:=do_syscall(syscall_nr_utimensat,dfd,TSysParam(path),TSysParam(@times),0); +{$endif sizeof(clong)<=4} +end; + + +Function futimens(fd: cint; const times:tkernel_timespecs):cint; +var + tsa: Array[0..1] of timespec; +begin +{$if sizeof(clong)<=4} + futimens:=do_syscall(syscall_nr_utimensat_time64,fd,TSysParam(nil),TSysParam(@times),0); + if (futimens>=0) or (fpgeterrno<>ESysENOSYS) then + exit; + { try 32 bit fall back } + tsa[0].tv_sec := times[0].tv_sec; + tsa[0].tv_nsec := times[0].tv_nsec; + tsa[1].tv_sec := times[1].tv_sec; + tsa[1].tv_nsec := times[1].tv_nsec; + futimens:=do_syscall(syscall_nr_utimensat,fd,TSysParam(nil),TSysParam(@tsa),0); +{$else sizeof(clong)<=4} + futimens:=do_syscall(syscall_nr_utimensat,fd,TSysParam(nil),TSysParam(@times),0); +{$endif sizeof(clong)<=4} +end; +{$endif android} +{$endif not FPC_USE_LIBC} end. + diff --git a/avx512-0037785/rtl/linux/m68k/cprt0.as b/avx512-0037785/rtl/linux/m68k/cprt0.as index 46f8ddc403..0c47f6b308 100644 --- a/avx512-0037785/rtl/linux/m68k/cprt0.as +++ b/avx512-0037785/rtl/linux/m68k/cprt0.as @@ -38,6 +38,7 @@ __entry: lea.l 8(%sp,%d0.l*4),%a0 move.l %a0,operatingsystem_parameter_envp move.l %sp,%a0 /* argv */ + move.l %sp,__stkptr pea (%sp) /* highest available stack address */ pea (%a1) /* termination function provided by kernel */ diff --git a/avx512-0037785/rtl/linux/m68k/dllprt0.as b/avx512-0037785/rtl/linux/m68k/dllprt0.as index c4f94ee050..e82b3b3f2b 100644 --- a/avx512-0037785/rtl/linux/m68k/dllprt0.as +++ b/avx512-0037785/rtl/linux/m68k/dllprt0.as @@ -24,6 +24,7 @@ _startlib: # This is a normal C function with args (argc,argv,envp) FPC_SHARED_LIB_START: link.w %a6,#0 + move.l %sp,__stkptr move.l 8(%fp),%d0 move.l %d0,operatingsystem_parameter_argc move.l 12(%fp),%d0 diff --git a/avx512-0037785/rtl/linux/mips/cprt0.as b/avx512-0037785/rtl/linux/mips/cprt0.as index 327adf1dcf..7cf2816df9 100644 --- a/avx512-0037785/rtl/linux/mips/cprt0.as +++ b/avx512-0037785/rtl/linux/mips/cprt0.as @@ -128,6 +128,11 @@ _start: .globl main_stub .type main_stub,@function main_stub: + /* load fp */ + move $s8,$sp + /* set __stkptr value to $s8 */ + lui $v0,%hi(__stkptr) + sw $s8,%lo(__stkptr)($v0) lui $v0,%hi(__fpc_ret_sp) sw $sp,%lo(__fpc_ret_sp)($v0) lui $v0,%hi(__fpc_ret_ra) diff --git a/avx512-0037785/rtl/linux/mips/prt0.as b/avx512-0037785/rtl/linux/mips/prt0.as index 17d57ef326..0b624a86a6 100644 --- a/avx512-0037785/rtl/linux/mips/prt0.as +++ b/avx512-0037785/rtl/linux/mips/prt0.as @@ -52,6 +52,7 @@ _dynamic_start: _start: /* load fp */ move $s8,$sp + /* set __stkptr value to $s8 */ lui $at,%hi(__stkptr) sw $s8,%lo(__stkptr)($at) diff --git a/avx512-0037785/rtl/linux/si_impl.inc b/avx512-0037785/rtl/linux/si_impl.inc index a727310551..2b19deaf10 100644 --- a/avx512-0037785/rtl/linux/si_impl.inc +++ b/avx512-0037785/rtl/linux/si_impl.inc @@ -16,7 +16,9 @@ procedure PascalMain; external name 'PASCALMAIN'; {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION} procedure SysEntry(constref info: TEntryInformation); external name 'FPC_SysEntry'; +{$ifndef FPC_USE_LIBC} procedure SysEntry_InitTLS(constref info: TEntryInformation); external name 'FPC_SysEntry_InitTLS'; +{$endif FPC_USE_LIBC} var InitFinalTable : record end; external name 'INITFINAL'; diff --git a/avx512-0037785/rtl/linux/system.pp b/avx512-0037785/rtl/linux/system.pp index caa4e116c7..4303c61147 100644 --- a/avx512-0037785/rtl/linux/system.pp +++ b/avx512-0037785/rtl/linux/system.pp @@ -125,6 +125,9 @@ procedure OsSetupEntryInformation(constref info: TEntryInformation); forward; TLS handling *****************************************************************************} +{ TLS initialization is not required if linking against libc } +{$if not defined(FPC_USE_LIBC)} + {$if defined(CPUARM)} {$define INITTLS} Function fpset_tls(p : pointer;size : SizeUInt):cint; @@ -185,6 +188,8 @@ begin end; {$endif defined(CPUX86_64)} +{$endif not FPC_USE_LIBC} + {$ifdef INITTLS} { This code initialized the TLS segment for single threaded and static programs. @@ -323,6 +328,8 @@ begin info.PascalMain(); end; + +{$ifndef FPC_USE_LIBC} procedure SysEntry_InitTLS(constref info: TEntryInformation);[public,alias:'FPC_SysEntry_InitTLS']; begin SetupEntryInformation(info); @@ -334,6 +341,7 @@ begin {$endif cpui386} info.PascalMain(); end; +{$endif FPC_USE_LIBC} {$else} var @@ -361,6 +369,7 @@ begin end; +{$ifdef FPC_USE_LIBC} procedure SysEntry_InitTLS(constref info: TEntryInformation);[public,alias:'FPC_SysEntry_InitTLS']; begin initialstkptr := info.OS.stkptr; @@ -375,6 +384,7 @@ begin {$endif cpui386} info.PascalMain(); end; +{$endif FPC_USE_LIBC} {$endif FPC_BOOTSTRAP_INDIRECT_ENTRY} diff --git a/avx512-0037785/rtl/linux/x86_64/si_prc.inc b/avx512-0037785/rtl/linux/x86_64/si_prc.inc index 1864e9d559..71804c1343 100644 --- a/avx512-0037785/rtl/linux/x86_64/si_prc.inc +++ b/avx512-0037785/rtl/linux/x86_64/si_prc.inc @@ -35,7 +35,9 @@ {$L abitag.o} +{$ifndef FPC_USE_LIBC} procedure InitTLS; [external name 'FPC_INITTLS']; +{$endif} {****************************************************************************** Process start/halt @@ -73,7 +75,11 @@ procedure _FPC_proc_start; assembler; nostackframe; public name '_start'; movq %r10,%rdi xorq %rbp, %rbp +{$ifdef FPC_USE_LIBC} + call SysEntry +{$else} call SysEntry_InitTLS +{$endif} {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION} popq %rsi { Pop the argument count. } movq operatingsystem_parameter_argc@GOTPCREL(%rip),%rax @@ -90,9 +96,9 @@ procedure _FPC_proc_start; assembler; nostackframe; public name '_start'; movq initialstkptr@GOTPCREL(%rip),%rax movq %rsp,(%rax) -{$if FPC_FULLVERSION>30200} +{$if (FPC_FULLVERSION>30200) and not defined(FPC_USE_LIBC)} call InitTLS -{$endif FPC_FULLVERSION>30200} +{$endif FPC_FULLVERSION>30200 and not FPC_USE_LIBC} xorq %rbp, %rbp call PASCALMAIN diff --git a/avx512-0037785/rtl/linux/x86_64/syscall.inc b/avx512-0037785/rtl/linux/x86_64/syscall.inc index aad7783a92..1812073032 100644 --- a/avx512-0037785/rtl/linux/x86_64/syscall.inc +++ b/avx512-0037785/rtl/linux/x86_64/syscall.inc @@ -20,9 +20,10 @@ procedure mcount; external name 'mcount'; {$endif FPC_PROFILE} -function FpSysCall(sysnr:TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL0']; +function FpSysCall(sysnr:TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL0']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr call mcount @@ -37,11 +38,13 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; -function FpSysCall(sysnr,param1 : TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL1']; +function FpSysCall(sysnr,param1 : TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL1']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr pushq param1 @@ -59,11 +62,13 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; -function FpSysCall(sysnr,param1,param2 : TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL2']; +function FpSysCall(sysnr,param1,param2 : TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL2']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr pushq param1 @@ -84,11 +89,13 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; -function FpSysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL3']; +function FpSysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL3']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr pushq param1 @@ -112,11 +119,13 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; -function FpSysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL4']; +function FpSysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL4']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr pushq param1 @@ -143,11 +152,13 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; -function FpSysCall(sysnr,param1,param2,param3,param4,param5 : TSysParam):TSysResult; assembler;[public,alias:'FPC_SYSCALL5']; +function FpSysCall(sysnr,param1,param2,param3,param4,param5 : TSysParam):TSysResult; assembler; nostackframe; [public,alias:'FPC_SYSCALL5']; asm + pushq %rax { keep stack aligned } {$ifdef FPC_PROFILE} pushq sysnr pushq param1 @@ -177,6 +188,7 @@ asm call seterrno@PLT movq $-1,%rax .LSyscOK: + popq %rcx { remove alignment } end; diff --git a/avx512-0037785/rtl/objpas/sysconst.pp b/avx512-0037785/rtl/objpas/sysconst.pp index 39b844dfa2..cefd14f79c 100644 --- a/avx512-0037785/rtl/objpas/sysconst.pp +++ b/avx512-0037785/rtl/objpas/sysconst.pp @@ -90,13 +90,13 @@ const SNoDynLibsSupport = 'Dynamic libraries not supported. Recompile program with dynamic library driver.'; SMissingWStringManager = 'Widestring manager not available. Recompile program with appropriate manager.'; SSigQuit = 'SIGQUIT signal received.'; - SObjectCheckError = 'Object reference is Nil'; + SObjectCheckError = 'Object reference is Nil or VMT is damaged'; SOSError = 'System error, (OS Code %d):'+LineEnding+'%s'; SOutOfMemory = 'Out of memory'; SOverflow = 'Floating point overflow'; SPrivilege = 'Privileged instruction'; SRangeError = 'Range check error'; - SStackOverflow = 'Stack overflow'; + SStackOverflow = 'Stack overflow or stack misalignment'; SSafecallException = 'Exception in safecall method'; SiconvError = 'iconv error'; SThreadError = 'Thread error'; diff --git a/avx512-0037785/rtl/objpas/sysutils/syshelpo.inc b/avx512-0037785/rtl/objpas/sysutils/syshelpo.inc index 0ab24ea753..497d0ef508 100644 --- a/avx512-0037785/rtl/objpas/sysutils/syshelpo.inc +++ b/avx512-0037785/rtl/objpas/sysutils/syshelpo.inc @@ -1,8 +1,12 @@ Class Function TORDINALHELPER.Parse(const AString: string): TORDINALTYPE; inline; static; +var + Error: Integer; begin - Result:=StrToInt(AString); + Val(AString,Result,Error); + if Error<>0 then + raise EConvertError.CreateFmt(SInvalidInteger,[AString]); end; Class Function TORDINALHELPER.Size: Integer; inline; static; @@ -14,7 +18,7 @@ end; Class Function TORDINALHELPER.ToString(const AValue: TORDINALTYPE): string; overload; inline; static; begin - Result:=IntToStr(AValue); + Str(AValue,Result); end; Class Function TORDINALHELPER.TryParse(const AString: string; out AValue: TORDINALTYPE): Boolean; inline; static; @@ -73,7 +77,7 @@ end; Function TORDINALHELPER.ToString: string; overload; inline; begin - Result:=IntToStr(Self); + Str(Self,Result); end; Function TORDINALHELPER.SetBit(const index: TORDINALBITINDEX) : TORDINALTYPE; inline; diff --git a/avx512-0037785/rtl/unix/oscdeclh.inc b/avx512-0037785/rtl/unix/oscdeclh.inc index 291e5e2f70..abfabe073a 100644 --- a/avx512-0037785/rtl/unix/oscdeclh.inc +++ b/avx512-0037785/rtl/unix/oscdeclh.inc @@ -180,4 +180,6 @@ const {$endif} function FpTime (tloc:ptime_t): time_t; cdecl; external clib name 'time'; - +{$if defined(linux)} + function FpSchedGetAffinity(pid : pid_t;cpusetsize : size_t;mask : pcpu_set_t) : cint; cdecl; external clib name 'sched_getaffinity'; +{$endif} diff --git a/avx512-0037785/rtl/unix/sysutils.pp b/avx512-0037785/rtl/unix/sysutils.pp index 68520a7e99..c35d28be79 100644 --- a/avx512-0037785/rtl/unix/sysutils.pp +++ b/avx512-0037785/rtl/unix/sysutils.pp @@ -55,6 +55,15 @@ uses {$DEFINE HAVECLOCKGETTIME} {$ENDIF} +{$if defined(LINUX)} + {$if sizeof(clong)<8} + {$DEFINE USE_STATX} + {$DEFINE USE_UTIMENSAT} + {$endif sizeof(clong)<=4} + + {$DEFINE USE_FUTIMES} +{$endif} + { Include platform independent interface part } {$i sysutilh.inc} @@ -547,12 +556,26 @@ begin end; end; + Function FileAge (Const FileName : RawByteString): Int64; Var Info : Stat; SystemFileName: RawByteString; +{$ifdef USE_STATX} + Infox : TStatx; +{$endif USE_STATX} begin SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName); + +{$ifdef USE_STATX} + { first try statx } + if (statx(AT_FDCWD,pchar(SystemFileName),0,STATX_MTIME or STATX_MODE,Infox)>=0) and not(fpS_ISDIR(Infox.stx_mode)) then + begin + Result:=Infox.stx_mtime.tv_sec; + exit; + end; +{$endif USE_STATX} + If (fpstat(pchar(SystemFileName),Info)<0) or fpS_ISDIR(info.st_mode) then exit(-1) else @@ -587,6 +610,36 @@ begin end; +{$ifdef USE_STATX} +Function LinuxToWinAttr (const FN : RawByteString; Const Info : TStatx) : Longint; +Var + LinkInfo : Stat; + nm : RawByteString; +begin + Result:=faArchive; + If fpS_ISDIR(Info.stx_mode) then + Result:=Result or faDirectory; + nm:=ExtractFileName(FN); + If (Length(nm)>=2) and + (nm[1]='.') and + (nm[2]<>'.') then + Result:=Result or faHidden; + If (Info.stx_Mode and S_IWUSR)=0 Then + Result:=Result or faReadOnly; + If fpS_ISSOCK(Info.stx_mode) or fpS_ISBLK(Info.stx_mode) or fpS_ISCHR(Info.stx_mode) or fpS_ISFIFO(Info.stx_mode) Then + Result:=Result or faSysFile; + If fpS_ISLNK(Info.stx_mode) Then + begin + Result:=Result or faSymLink; + // Windows reports if the link points to a directory. + { as we are only interested in the st_mode field here, we do not need to use statx } + if (fpstat(pchar(FN),LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then + Result := Result or faDirectory; + end; +end; +{$endif USE_STATX} + + function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean; var Info : Stat; @@ -874,26 +927,54 @@ end; Function FindGetFileInfo(const s: RawByteString; var f: TAbstractSearchRec; var Name: RawByteString):boolean; Var +{$ifdef USE_STATX} + stx : linux.tstatx; +{$endif USE_STATX} st : baseunix.stat; WinAttr : longint; begin +{$ifdef USE_STATX} if Assigned(f.FindHandle) and ( (PUnixFindData(F.FindHandle)^.searchattr and faSymlink) > 0) then - FindGetFileInfo:=(fplstat(pointer(s),st)=0) + FindGetFileInfo:=statx(AT_FDCWD,pointer(s),AT_SYMLINK_NOFOLLOW,STATX_ALL,stx)=0 else - FindGetFileInfo:=(fpstat(pointer(s),st)=0); - if not FindGetFileInfo then - exit; - WinAttr:=LinuxToWinAttr(s,st); - FindGetFileInfo:=(WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0; - + FindGetFileInfo:=statx(AT_FDCWD,pointer(s),0,STATX_ALL,stx)=0; if FindGetFileInfo then begin - Name:=ExtractFileName(s); - f.Attr:=WinAttr; - f.Size:=st.st_Size; - f.Mode:=st.st_mode; - f.Time:=st.st_mtime; - FindGetFileInfo:=true; + WinAttr:=LinuxToWinAttr(s,stx); + FindGetFileInfo:=(WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0; + + if FindGetFileInfo then + begin + Name:=ExtractFileName(s); + f.Attr:=WinAttr; + f.Size:=stx.stx_Size; + f.Mode:=stx.stx_mode; + f.Time:=stx.stx_mtime.tv_sec; + FindGetFileInfo:=true; + end; + end + { no statx? try stat } + else if fpgeterrno=ESysENOSYS then +{$endif USE_STATX} + begin + if Assigned(f.FindHandle) and ( (PUnixFindData(F.FindHandle)^.searchattr and faSymlink) > 0) then + FindGetFileInfo:=(fplstat(pointer(s),st)=0) + else + FindGetFileInfo:=(fpstat(pointer(s),st)=0); + if not FindGetFileInfo then + exit; + WinAttr:=LinuxToWinAttr(s,st); + FindGetFileInfo:=(WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0; + + if FindGetFileInfo then + begin + Name:=ExtractFileName(s); + f.Attr:=WinAttr; + f.Size:=st.st_Size; + f.Mode:=st.st_mode; + f.Time:=st.st_mtime; + FindGetFileInfo:=true; + end; end; end; @@ -996,22 +1077,44 @@ End; Function FileGetDate (Handle : Longint) : Int64; - -Var Info : Stat; - +Var + Info : Stat; +{$ifdef USE_STATX} + Infox : TStatx; +{$endif USE_STATX} + Char0 : char; begin - If (fpFStat(Handle,Info))<0 then - Result:=-1 - else - Result:=Info.st_Mtime; + Result:=-1; +{$ifdef USE_STATX} + Char0:=#0; + if statx(Handle,@Char0,AT_EMPTY_PATH,STATX_MTIME,Infox)=0 then + Result:=Infox.stx_Mtime.tv_sec + else if fpgeterrno=ESysENOSYS then +{$endif USE_STATX} + begin + If fpFStat(Handle,Info)=0 then + Result:=Info.st_Mtime; + end; end; Function FileSetDate (Handle : Longint;Age : Int64) : Longint; - +{$ifdef USE_FUTIMES} +var + times : tkernel_timespecs; +{$endif USE_FUTIMES} begin - // Impossible under Linux from FileHandle !! + Result:=0; +{$ifdef USE_FUTIMES} + times[0].tv_sec:=Age; + times[0].tv_nsec:=0; + times[1].tv_sec:=Age; + times[1].tv_nsec:=0; + if futimens(Handle,times) = -1 then + Result:=fpgeterrno; +{$else USE_FUTIMES} FileSetDate:=-1; +{$endif USE_FUTIMES} end; @@ -1068,14 +1171,29 @@ end; Function FileSetDate (Const FileName : RawByteString; Age : Int64) : Longint; var SystemFileName: RawByteString; +{$ifdef USE_UTIMENSAT} + times : tkernel_timespecs; +{$endif USE_UTIMENSAT} t: TUTimBuf; begin SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName); Result:=0; - t.actime:= Age; - t.modtime:=Age; - if fputime(PChar(SystemFileName), @t) = -1 then +{$ifdef USE_UTIMENSAT} + times[0].tv_sec:=Age; + times[0].tv_nsec:=0; + times[1].tv_sec:=Age; + times[1].tv_nsec:=0; + if utimensat(AT_FDCWD,PChar(SystemFileName),times,0) = -1 then Result:=fpgeterrno; + if fpgeterrno=ESysENOSYS then +{$endif USE_UTIMENSAT} + begin + Result:=0; + t.actime:= Age; + t.modtime:=Age; + if fputime(PChar(SystemFileName), @t) = -1 then + Result:=fpgeterrno; + end end; {**************************************************************************** diff --git a/avx512-0037785/tests/Makefile b/avx512-0037785/tests/Makefile index b9676a929a..e908b07b74 100644 --- a/avx512-0037785/tests/Makefile +++ b/avx512-0037785/tests/Makefile @@ -2423,9 +2423,9 @@ LOGEXT=.testlog .tbslog .tbflog .webtbslog .webtbflog TESTUNITDIRS=system dos crt objects strings sysutils math sharemem strutils matrix lineinfo ucomplex fpwidestring cpu fmtbcd windows classes character dateutil fpcunit softfpu variants sortbase sortalgs linux unixutil types nullable TESTDIRECTDIRS= TESTSUBDIRS=cg cg/variants cg/cdecl cpu16 cpu16/i8086 library opt $(addprefix units/,$(TESTUNITDIRS)) -TESTPACKAGESDIRS=win-base webtbs hash fcl-registry fcl-process zlib fcl-db fcl-xml cocoaint bzip2 +TESTPACKAGESDIRS=win-base webtbs hash fcl-registry fcl-process zlib fcl-db fcl-xml cocoaint bzip2 fcl-net TESTPACKAGESUBDIRS=$(addprefix packages/,$(TESTPACKAGESDIRS)) -TESTPACKAGESDIRECTDIRS=rtl-objpas rtl-generics hash regexpr +TESTPACKAGESDIRECTDIRS=rtl-objpas rtl-generics hash regexpr fcl-registry TESTPACKAGESDIRECTSUBDIRS=$(addprefix ../packages/,$(addsuffix /tests,$(TESTPACKAGESDIRECTDIRS))) ifdef QUICKTEST export QUICKTEST diff --git a/avx512-0037785/tests/Makefile.fpc b/avx512-0037785/tests/Makefile.fpc index 5e6dd2bd2f..15e765d5c4 100644 --- a/avx512-0037785/tests/Makefile.fpc +++ b/avx512-0037785/tests/Makefile.fpc @@ -162,9 +162,9 @@ LOGEXT=.testlog .tbslog .tbflog .webtbslog .webtbflog TESTUNITDIRS=system dos crt objects strings sysutils math sharemem strutils matrix lineinfo ucomplex fpwidestring cpu fmtbcd windows classes character dateutil fpcunit softfpu variants sortbase sortalgs linux unixutil types nullable TESTDIRECTDIRS= TESTSUBDIRS=cg cg/variants cg/cdecl cpu16 cpu16/i8086 library opt $(addprefix units/,$(TESTUNITDIRS)) -TESTPACKAGESDIRS=win-base webtbs hash fcl-registry fcl-process zlib fcl-db fcl-xml cocoaint bzip2 +TESTPACKAGESDIRS=win-base webtbs hash fcl-registry fcl-process zlib fcl-db fcl-xml cocoaint bzip2 fcl-net TESTPACKAGESUBDIRS=$(addprefix packages/,$(TESTPACKAGESDIRS)) -TESTPACKAGESDIRECTDIRS=rtl-objpas rtl-generics hash regexpr +TESTPACKAGESDIRECTDIRS=rtl-objpas rtl-generics hash regexpr fcl-registry TESTPACKAGESDIRECTSUBDIRS=$(addprefix ../packages/,$(addsuffix /tests,$(TESTPACKAGESDIRECTDIRS))) ifdef QUICKTEST diff --git a/avx512-0037785/tests/test/cg/tpara4.pp b/avx512-0037785/tests/test/cg/tpara4.pp new file mode 100644 index 0000000000..f175a553eb --- /dev/null +++ b/avx512-0037785/tests/test/cg/tpara4.pp @@ -0,0 +1,22 @@ +{ This test ensures that a "const TVarData" parameter is passed as a reference. + This is required for Delphi compatibility as implementers of IVarInvokable or + inheritors of TInvokableVariantType need to modify the variant data by using + a pointer to the TVarData because it's passed as const and thus not modifyable + by itself. + This behavior is documented in so far as the C++ builder documentation shows + that the same parameter is implemented as "const&". } + +program tpara4; + +var + d: TVarData; + +procedure Test(const v: TVarData); +begin + if @d <> @v then + Halt(1); +end; + +begin + Test(d); +end. diff --git a/avx512-0037785/tests/test/theapthread.pp b/avx512-0037785/tests/test/theapthread.pp index 44f51bf000..36689148ab 100644 --- a/avx512-0037785/tests/test/theapthread.pp +++ b/avx512-0037785/tests/test/theapthread.pp @@ -15,12 +15,14 @@ type tpair = class; tproducethread = class(tthread) + running: boolean; pair: tpair; constructor create(apair: tpair); procedure execute; override; end; tconsumethread = class(tthread) + running: boolean; pair: tpair; constructor create(apair: tpair); procedure execute; override; @@ -197,11 +199,13 @@ end; procedure tproducethread.execute; begin + running:=true; producer(pair); end; procedure tconsumethread.execute; begin + running:=true; consumer(pair); end; @@ -221,7 +225,12 @@ begin pairs[i] := tpair.create; for i := low(pairs) to high(pairs) do pairs[i].resume; - sleep(1500); + + { wait till all threads are really resumed } + for i := low(pairs) to high(pairs) do + while not(pairs[i].produce_thread.running) or not(pairs[i].consume_thread.running) do + sleep(100); + done := true; for i := low(pairs) to high(pairs) do begin diff --git a/avx512-0037785/tests/test/units/linux/tfutimesen.pp b/avx512-0037785/tests/test/units/linux/tfutimesen.pp new file mode 100644 index 0000000000..797f51fba3 --- /dev/null +++ b/avx512-0037785/tests/test/units/linux/tfutimesen.pp @@ -0,0 +1,84 @@ +{ %target=linux } +uses + ctypes,baseunix,linux; + +var + un : utsname; + res : cint; + f1,f2 : text; + err : word; + mystatx1,mystatx2 : tstatx; + times : tkernel_timespecs; + st,major,minor : string; + i,p,e : longint; + major_release, minor_release : longint; +begin + fpuname(un); + st:=un.release; + for i:=1 to UTSNAME_LENGTH do + if st[i]='.' then + begin + p:=i; + major:=system.copy(st,1,p-1); + system.val(major,major_release,err); + if err<>0 then + begin + writeln('Unable to parse first part of linux version ',st,'(',major,') correctly'); + halt(2); + end; + break; + end; + + for i:=p+1 to UTSNAME_LENGTH do + if st[i]='.' then + begin + e:=i; + minor:=system.copy(st,p+1,e-p-1); + system.val(minor,minor_release,err); + if err<>0 then + begin + writeln('Unable to second part of parse linux version ',st,'i(',minor,') correctly'); + halt(2); + end; + break; + end; + if (major_release<4) or ((major_release=4) and (minor_release<11)) then + begin + writeln('This version of Linux: ',st,' does not have fstatx syscall'); + halt(0); + end + else + writeln('This linux version ',st,' should support statx syscall'); + + assign(f1,'tutimensat1.txt'); + rewrite(f1); + write(f1,'ccccc'); + assign(f2,'tutimensat2.txt'); + rewrite(f2); + write(f2,'ccccc'); + + res:=statx(AT_FDCWD,'tutimensat1.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx1); + if res<>0 then + halt(1); + times[0].tv_sec:=mystatx1.stx_atime.tv_sec; + times[0].tv_nsec:=mystatx1.stx_atime.tv_nsec; + times[1].tv_sec:=mystatx1.stx_mtime.tv_sec; + times[1].tv_nsec:=mystatx1.stx_mtime.tv_nsec; + res:=futimens(textrec(f2).handle,times); + if res<>0 then + halt(1); + res:=statx(AT_FDCWD,'tutimensat2.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx2); + if res<>0 then + halt(1); + + close(f1); + close(f2); + + erase(f1); + erase(f2); + + if (mystatx1.stx_atime.tv_sec<>mystatx2.stx_atime.tv_sec) or (mystatx1.stx_atime.tv_nsec<>mystatx2.stx_atime.tv_nsec) or + (mystatx1.stx_mtime.tv_sec<>mystatx2.stx_mtime.tv_sec) or (mystatx1.stx_mtime.tv_nsec<>mystatx2.stx_mtime.tv_nsec) then + halt(1); + writeln('ok'); +end. diff --git a/avx512-0037785/tests/test/units/linux/tstatx.pp b/avx512-0037785/tests/test/units/linux/tstatx.pp index 360b11a356..78798f08c3 100644 --- a/avx512-0037785/tests/test/units/linux/tstatx.pp +++ b/avx512-0037785/tests/test/units/linux/tstatx.pp @@ -1,10 +1,10 @@ { %target=linux } uses ctypes,baseunix,linux; - + var un : utsname; - mystatx : statx; + mystatx : tstatx; res : cint; f : text; st,major,minor : string; @@ -21,13 +21,13 @@ begin major:=system.copy(st,1,p-1); system.val(major,major_release,err); if err<>0 then - begin + begin writeln('Unable to parse first part of linux version ',st,'(',major,') correctly'); halt(2); end; break; end; - + for i:=p+1 to UTSNAME_LENGTH do if st[i]='.' then begin @@ -35,25 +35,25 @@ begin minor:=system.copy(st,p+1,e-p-1); system.val(minor,minor_release,err); if err<>0 then - begin + begin writeln('Unable to second part of parse linux version ',st,'i(',minor,') correctly'); halt(2); end; break; end; - if (major_release<4) or (minor_release<11) then + if (major_release<4) or ((major_release=4) and (minor_release<11)) then begin writeln('This version of Linux: ',st,' does not have fstatx syscall'); halt(0); end else writeln('This linux version ',st,' should support statx syscall'); - + assign(f,'test.txt'); rewrite(f); write(f,'ccccc'); close(f); - res:=fpstatx(AT_FDCWD,'test.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx); + res:=statx(AT_FDCWD,'test.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx); erase(f); if res<>0 then begin diff --git a/avx512-0037785/tests/test/units/linux/tutimensat.pp b/avx512-0037785/tests/test/units/linux/tutimensat.pp new file mode 100644 index 0000000000..e7fc443bcb --- /dev/null +++ b/avx512-0037785/tests/test/units/linux/tutimensat.pp @@ -0,0 +1,83 @@ +{ %target=linux } +uses + ctypes,baseunix,linux; + +var + un : utsname; + res : cint; + f1,f2 : text; + err : word; + mystatx1,mystatx2 : tstatx; + times : tkernel_timespecs; + st,major,minor : string; + i,p,e : longint; + major_release, minor_release : longint; +begin + fpuname(un); + st:=un.release; + for i:=1 to UTSNAME_LENGTH do + if st[i]='.' then + begin + p:=i; + major:=system.copy(st,1,p-1); + system.val(major,major_release,err); + if err<>0 then + begin + writeln('Unable to parse first part of linux version ',st,'(',major,') correctly'); + halt(2); + end; + break; + end; + + for i:=p+1 to UTSNAME_LENGTH do + if st[i]='.' then + begin + e:=i; + minor:=system.copy(st,p+1,e-p-1); + system.val(minor,minor_release,err); + if err<>0 then + begin + writeln('Unable to second part of parse linux version ',st,'i(',minor,') correctly'); + halt(2); + end; + break; + end; + if (major_release<4) or ((major_release=4) and (minor_release<11)) then + begin + writeln('This version of Linux: ',st,' does not have fstatx syscall'); + halt(0); + end + else + writeln('This linux version ',st,' should support statx syscall'); + + assign(f1,'tutimensat1.txt'); + rewrite(f1); + write(f1,'ccccc'); + close(f1); + assign(f2,'tutimensat2.txt'); + rewrite(f2); + write(f2,'ccccc'); + close(f2); + + res:=statx(AT_FDCWD,'tutimensat1.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx1); + if res<>0 then + halt(1); + times[0].tv_sec:=mystatx1.stx_atime.tv_sec; + times[0].tv_nsec:=mystatx1.stx_atime.tv_nsec; + times[1].tv_sec:=mystatx1.stx_mtime.tv_sec; + times[1].tv_nsec:=mystatx1.stx_mtime.tv_nsec; + res:=utimensat(AT_FDCWD,'tutimensat2.txt',times,0); + if res<>0 then + halt(1); + res:=statx(AT_FDCWD,'tutimensat2.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx2); + if res<>0 then + halt(1); + + erase(f1); + erase(f2); + + if (mystatx1.stx_atime.tv_sec<>mystatx2.stx_atime.tv_sec) or (mystatx1.stx_atime.tv_nsec<>mystatx2.stx_atime.tv_nsec) or + (mystatx1.stx_mtime.tv_sec<>mystatx2.stx_mtime.tv_sec) or (mystatx1.stx_mtime.tv_nsec<>mystatx2.stx_mtime.tv_nsec) then + halt(1); + writeln('ok'); +end. diff --git a/avx512-0037785/tests/test/units/sysutils/tfile1.pp b/avx512-0037785/tests/test/units/sysutils/tfile1.pp index 578976f2c5..ddca3956e6 100644 --- a/avx512-0037785/tests/test/units/sysutils/tfile1.pp +++ b/avx512-0037785/tests/test/units/sysutils/tfile1.pp @@ -32,6 +32,19 @@ BEGIN if FileSetDate('datetest.dat', DateTimeToFileDate(dateTime))<>0 then do_error(1002); + dateTime := IncMonth(Now, -1); + Assign(f,'datetest.dat'); + Rewrite(f); + if FileSetDate(filerec(f).handle, DateTimeToFileDate(dateTime))<>0 then + do_error(1003); + Close(f); + + Assign(f,'datetest.dat'); + Reset(f); + if FileGetDate(filerec(f).handle)<>DateTimeToFileDate(dateTime) then + do_error(1004); + Close(f); + if FileExists('datetest.dat') then begin Assign(f,'datetest.dat'); diff --git a/avx512-0037785/tests/test/units/sysutils/tfileage.pp b/avx512-0037785/tests/test/units/sysutils/tfileage.pp new file mode 100644 index 0000000000..7710082ea6 --- /dev/null +++ b/avx512-0037785/tests/test/units/sysutils/tfileage.pp @@ -0,0 +1,18 @@ +uses + sysutils; +begin + if 3600*24*(now()-FileDateToDateTime(FileAge(paramstr(0))))>7200 then + begin + writeln('FileAge returns: ',FileDateToDateTime(FileAge(paramstr(0)))); + writeln('Compilation time and run time differ too much, SysUtils.FileAge buggy?'); + halt(1); + end; + + { test with relative path } + if 3600*24*(now()-FileDateToDateTime(FileAge(ExtractRelativePath(GetCurrentDir+DirectorySeparator,paramstr(0)))))>7200 then + begin + writeln('FileAge returns: ',FileDateToDateTime(FileAge(paramstr(0)))); + writeln('Compilation time and run time differ too much, SysUtils.FileAge buggy?'); + halt(1); + end; +end. diff --git a/avx512-0037785/tests/utils/testsuite/utests.pp b/avx512-0037785/tests/utils/testsuite/utests.pp index e40f57922c..cca795028b 100644 --- a/avx512-0037785/tests/utils/testsuite/utests.pp +++ b/avx512-0037785/tests/utils/testsuite/utests.pp @@ -153,13 +153,16 @@ const faction_compare_with_next = 6; faction_compare2_with_previous = 7; faction_compare2_with_next = 8; + faction_compare_both_with_previous = 9; + faction_compare_both_with_next = 10; + Function TestResultsTableName(const RunId : String) : string; var RunIDVal : qword; Error : word; begin - system.val (RunId,RunIdVal,error); + system.val (Trim(RunId),RunIdVal,error); if (error<>0) then result:='ErrorTable' else if (RunIdVal <= LastOldTestRun) then @@ -347,6 +350,18 @@ begin FCompareRunID:=FNext2RunID; ShowRunComparison; end; + faction_compare_both_with_previous : + begin + FRunID:=FPreviousRunID; + FCompareRunID:=FPrevious2RunID; + ShowRunComparison; + end; + faction_compare_both_with_next : + begin + FRunID:=FNextRunID; + FCompareRunID:=FNext2RunID; + ShowRunComparison; + end; {$ifdef TEST} 98 : begin @@ -402,6 +417,10 @@ begin FAction:=faction_compare2_with_previous else if S='Compare_right_to_next' then FAction:=faction_compare2_with_next + else if S='Compare_both_to_previous' then + FAction:=faction_compare_both_with_previous + else if S='Compare_both_to_next' then + FAction:=faction_compare_both_with_next else FAction:=StrToIntDef(S,0); S:=RequestVariables['limit']; @@ -1134,7 +1153,7 @@ Const SGetRunData = 'SELECT TU_ID,TU_DATE,TC_NAME,TO_NAME,' + 'TU_SUBMITTER,TU_MACHINE,TU_COMMENT,TV_VERSION,'+ 'TU_CATEGORY_FK,TU_SVNCOMPILERREVISION,TU_SVNRTLREVISION,'+ - 'TU_COMPILERDATE,'+ + 'TU_COMPILERDATE,TU_COMPILERFULLVERSION,'+ 'TU_SVNPACKAGESREVISION,TU_SVNTESTSREVISION,'+ '(TU_SUCCESSFULLYFAILED+TU_SUCCESFULLYCOMPILED+TU_SUCCESSFULLYRUN) AS OK,'+ '(TU_FAILEDTOCOMPILE+TU_FAILEDTORUN+TU_FAILEDTOFAIL) as Failed,'+ @@ -1150,12 +1169,70 @@ Const Var - Q1,Q2 : TSQLQuery; + Q1, Q2 : TSQLQuery; F : TField; - SC : string; - Date1, Date2: TDateTime; - AddNewPar : boolean; - CompilerDate1, CompilerDate2: TDateTime; + SC, FRight : string; + Date1, Date2 : TDateTime; + AddNewPar, same_date : boolean; + CompilerDate1, CompilerDate2 : TDateTime; + + procedure EmitOneRow(RowTitle,FieldLeft,FieldRight : String; is_same : boolean); + var + FieldColor : string; + begin + if (FieldRight='') then + FieldColor:='' + else if is_same then + FieldColor:='style="color:green;"' + else + FieldColor:='style="color:red;"'; + With FHTMLWriter do + begin + RowNext; + if FieldColor<>'' then + begin + TagStart('TD',FieldColor); + end + else + CellStart; + LDumpLn(RowTitle); + if FieldColor<>'' then + begin + CellEnd; + TagStart('TD',FieldColor); + end + else + CellNext; + LDumpLn(FieldLeft); + if FieldColor<>'' then + begin + CellEnd; + TagStart('TD',FieldColor); + end + else + CellNext; + LDumpLn(FieldRight); + CellEnd; + end; + end; + procedure EmitOneRow(RowTitle,FieldLeft,FieldRight : String); + var + is_same : boolean; + begin + is_same:=(FieldLeft=FieldRight); + EmitOneRow(RowTitle,FieldLeft,FieldRight,is_same); + end; + procedure EmitRow(RowTitle,FieldName : String); + var + FieldLeft, FieldRight : String; + begin + FieldLeft:=Q1.FieldByName(FieldName).AsString; + if Q2=nil then + FieldRight:='' + else + FieldRight:=Q2.FieldByName(FieldName).AsString; + EmitOneRow(RowTitle,FieldLeft,FieldRight); + end; begin Result:=(FRunID<>''); If Result then @@ -1191,172 +1268,99 @@ begin CellNext; EmitInput('run2id',FCompareRunID); CellEnd; - RowNext; - CellStart; - DumpLn('Operating system:'); - CellNext; - DumpLn(Q1.FieldByName('TO_NAME').AsString); - CellNext; - if Q2 <> nil then - DumpLn(Q2.FieldByName('TO_NAME').AsString); - CellEnd; - RowNext; - CellStart; - DumpLn('Processor:'); - CellNext; - DumpLn(Q1.FieldByName('TC_NAME').AsString); - CellNext; - if Q2 <> nil then - DumpLn(Q2.FieldByName('TC_NAME').AsString); - CellEnd; - RowNext; - CellStart; - DumpLn('Version:'); - CellNext; - DumpLn(Q1.FieldByNAme('TV_VERSION').AsString); - CellNext; - if Q2 <> nil then - DumpLn(Q2.FieldByNAme('TV_VERSION').AsString); - CellEnd; - RowNext; - CellStart; - DumpLn('Fails/OK/Total:'); - CellNext; - Dump(Q1.FieldByName('Failed').AsString); - Dump('/'+Q1.FieldByName('OK').AsString); - DumpLn('/'+Q1.FieldByName('Total').AsString); - CellNext; - if Q2 <> nil then - begin - Dump(Q2.FieldByName('Failed').AsString); - Dump('/'+Q2.FieldByName('Ok').AsString); - DumpLn('/'+Q2.FieldByName('Total').AsString); - end; - CellEnd; - RowNext; - CellStart; - DumpLn('Comment:'); - CellNext; - DumpLn(Q1.FieldByName('TU_COMMENT').AsString); - CellNext; - if Q2 <> nil then - DumpLn(Q2.FieldByName('TU_COMMENT').AsString); - CellEnd; - RowNext; - CellStart; - DumpLn('Machine:'); - CellNext; - DumpLn(Q1.FieldByName('TU_MACHINE').AsString); - CellNext; - if Q2 <> nil then - DumpLn(Q2.FieldByName('TU_MACHINE').AsString); - CellEnd; - if GetCategoryName(FCategory)<>'All' then + EmitRow('Operating system:','TO_NAME'); + EmitRow('Processor:','TC_NAME'); + EmitRow('Version:','TV_VERSION'); + if Q2 = nil then + FRight:='' + else begin - RowNext; - CellStart; - DumpLn('Category:'); - CellNext; - DumpLn(GetCategoryName(Q1.FieldByName('TU_CATEGORY_FK').AsString)); - CellNext; - if Q2 <> nil then - DumpLn(GetCategoryName(Q2.FieldByName('TU_CATEGORY_FK').AsString)); - CellEnd; + FRight:=Q2.FieldByName('Failed').AsString+ + '/'+Q2.FieldByName('Ok').AsString+ + '/'+Q2.FieldByName('Total').AsString; end; + EmitOneRow('Fails/OK/Total:', + Q1.FieldByName('Failed').AsString+ + '/'+Q1.FieldByName('OK').AsString+ + '/'+Q1.FieldByName('Total').AsString, + FRight); + EmitRow('Version:','TV_VERSION'); + EmitRow('Full version:','TU_COMPILERFULLVERSION'); + EmitRow('Comment:','TU_COMMENT'); + EmitRow('Machine:','TU_MACHINE'); + if GetCategoryName(FCategory)<>'All' then + EmitRow('Category:','TU_CATEGORY_FK'); If GetCategoryName(FCategory)<>'DB' then begin - RowNext; - CellStart; - DumpLn('SVN Revisions:'); - CellNext; - SC:=Q1.FieldByName('svnrev').AsString; - if (SC<>'') then - FormatSVNData(SC); - LDumpLn(SC); - CellNext; - if Q2 <> nil then - begin - SC:=Q2.FieldByName('svnrev').AsString; - FormatSVNData(SC); - LDumpLn(SC); - end; - CellEnd; - end; - RowNext; - CellStart; - DumpLn('Submitter:'); - CellNext; - DumpLn(Q1.FieldByName('TU_SUBMITTER').AsString); - CellNext; + SC:=Q1.FieldByName('svnrev').AsString; + if (SC<>'') then + FormatSVNData(SC); if Q2 <> nil then - DumpLn(Q2.FieldByName('TU_SUBMITTER').AsString); - CellEnd; - RowNext; - CellStart; - DumpLn('Date:'); - CellNext; - F := Q1.FieldByName('TU_DATE'); - Date1 := F.AsDateTime; - DumpLn(F.AsString); - F := Q1.FieldByName('TU_COMPILERDATE'); + begin + FRight:=Q2.FieldByName('svnrev').AsString; + FormatSVNData(FRight); + end + else + FRight:=''; + EmitOneRow('SVN revisions:',SC,FRight); + end; + EmitRow('Submitter:','TU_SUBMITTER'); + F := Q1.FieldByName('TU_DATE'); + Date1 := F.AsDateTime; + SC:=F.AsString; + F := Q1.FieldByName('TU_COMPILERDATE'); + Try + CompilerDate1 := F.AsDateTime; + if not SameDate(Date1,CompilerDate1) then + SC:=SC+' <> '+F.AsString; + Except + { Not a valid date, do nothing } + end; + if Q2 = nil then + FRight:='' + else + begin + F := Q2.FieldByName('TU_DATE'); + Date2 := F.AsDateTime; + FRight:= F.AsString; + F := Q2.FieldByName('TU_COMPILERDATE'); Try - CompilerDate1 := F.AsDateTime; - if not SameDate(Date1,CompilerDate1) then - DumpLn(' <> '+F.AsString); + CompilerDate2 := F.AsDateTime; + if not SameDate(Date2,CompilerDate2) then + FRight:=FRight+' <> '+F.AsString; Except { Not a valid date, do nothing } end; - CellNext; - if Q2 <> nil then - begin - F := Q2.FieldByName('TU_DATE'); - Date2 := F.AsDateTime; - DumpLn(F.AsString); - F := Q2.FieldByName('TU_COMPILERDATE'); - Try - CompilerDate2 := F.AsDateTime; - if not SameDate(Date2,CompilerDate2) then - DumpLn(' <> '+F.AsString); - Except - { Not a valid date, do nothing } - end; - end; - CellEnd; - RowNext; - CellStart; - DumpLn('Previous run:'); - CellNext; - FPreviousRunID:=GetPreviousRunID(FRunID); - if FPreviousRunID<>'' then - EmitHiddenVar('previousrunid',FPreviousRunID); - DumpLn(FPreviousRunID); - CellNext; - if (FCompareRunID<>'') then - begin - FPrevious2RunID:=GetPreviousRunID(FCompareRunID); - DumpLn(FPrevious2RunID); - if FPrevious2RunID <> '' then - EmitHiddenVar('previous2runid',FPrevious2RunID); - end; - CellEnd; - RowNext; - CellStart; - DumpLn('Next run:'); - CellNext; - FNextRunID:=GetNextRunID(FRunID); - if FNextRunID<>'' then - EmitHiddenVar('nextrunid',FNextRunID); - DumpLn(FNextRunID); - CellNext; - if (FCompareRunID<>'') then - begin - FNext2RunID:=GetNextRunID(FCompareRunID); - DumpLn(FNext2RunID); - if FNext2RunID <> '' then - EmitHiddenVar('next2runid',FNext2RunID); - end; - CellEnd; + end; + same_date:=(Copy(SC,1,10)=Copy(FRight,1,10)); + EmitOneRow('Date:',SC,FRight,same_date); + FPreviousRunID:=GetPreviousRunID(FRunID); + if FPreviousRunID<>'' then + EmitHiddenVar('previousrunid',FPreviousRunID); + SC:=FPreviousRunID; + if (FCompareRunID<>'') then + begin + FPrevious2RunID:=GetPreviousRunID(FCompareRunID); + FRight:=FPrevious2RunID; + if FPrevious2RunID <> '' then + EmitHiddenVar('previous2runid',FPrevious2RunID); + end + else + FRight:=''; + EmitOneRow('Previous run:',SC,FRight); + FNextRunID:=GetNextRunID(FRunID); + if FNextRunID<>'' then + EmitHiddenVar('nextrunid',FNextRunID); + SC:=FNextRunID; + if (FCompareRunID<>'') then + begin + FNext2RunID:=GetNextRunID(FCompareRunID); + FRight:=FNext2RunID; + if FNext2RunID <> '' then + EmitHiddenVar('next2runid',FNext2RunID); + end; + EmitOneRow('Next run:',SC,FRight); RowEnd; TableEnd; ParagraphStart; @@ -1397,7 +1401,22 @@ begin ParaGraphStart; end; - EmitSubmitButton('action','Show/Compare'); + if (FPrevious2RunID<>'') and (FPreviousRunId<>'') then + begin + EmitSubmitButton('action','Compare_both_to_previous'); + AddNewPar:=true; + end; + if (FNext2RunID<>'') and (FNextRunId<>'') then + begin + EmitSubmitButton('action','Compare_both_to_next'); + AddNewPar:=true; + end; + if AddNewPar then + begin + ParagraphEnd; + ParaGraphStart; + end; + EmitSubmitButton('action','Show/Compare'); if FTestFileID<>'' then EmitSubmitButton('action','View_history'); EmitResetButton('','Reset form'); @@ -1524,7 +1543,7 @@ begin finally Free; end; - If Not (FRunCount=0) and not (FNoSkipped or FOnlyFailed) then + If Not (FRunCount=0) and not (FNoSkipped and FOnlyFailed) then begin ParaGraphStart; TagStart('IMG',Format('Src="'+TestsuiteCGIURL+ @@ -2916,10 +2935,6 @@ Procedure TTestSuite.DoDrawPie(Img : TFPCustomImage; Skipped,Failed,Total : Inte Var Cnv : TFPImageCanvas; - W,H,FH,CR,ra : Integer; - A1,A2,FR,SR,PR : Double; - R : TRect; - F : TFreeTypeFont; Procedure AddPie(X,Y,R : Integer; AStart,AStop : Double; Col : TFPColor); @@ -2927,14 +2942,14 @@ Var DX,Dy : Integer; begin - DX:=Round(R*Cos(A1)); - DY:=Round(R*Sin(A1)); + DX:=Round(R*Cos(AStart)); + DY:=Round(R*Sin(AStart)); Cnv.Line(X,Y,X+DX,Y-DY); - DX:=Round(Ra*Cos(A2)); - DY:=Round(Ra*Sin(A2)); + DX:=Round(R*Cos(AStop)); + DY:=Round(R*Sin(AStop)); Cnv.Line(X,Y,X+DX,Y-Dy); - DX:=Round(R/2*Cos((A1+A2)/2)); - DY:=Round(R/2*Sin((A1+A2)/2)); + DX:=Round(R/2*Cos((AStart+AStop)/2)); + DY:=Round(R/2*Sin((AStart+AStop)/2)); Cnv.Brush.FpColor:=Col; Cnv.FloodFill(X+DX,Y-DY); end; @@ -2945,7 +2960,11 @@ Var Result:=(2*Pi*(F/T)) end; - +Var + W,H,FH,CR,RA : Integer; + A1,A2,FR,SR,PR : Double; + R : TRect; + F : TFreeTypeFont; begin F:=TFreeTypeFont.Create; @@ -3010,7 +3029,12 @@ begin Writeln(stdout,'Setting brush style'); system.flush(stdout); end; - cnv.brush.FPColor:=colRed; + cnv.brush.FPColor:=colDkGray; + SR:=Skipped/Total; + FR:=Failed/Total; + PR:=1-SR-FR; + cnv.font.FPColor:=colDkGray; + Cnv.Textout(1,FH*2,Format('%d Skipped (%3.1f%%)',[Skipped,SR*100])); // cnv.pen.width:=1; // Writeln('Drawing ellipse'); Cnv.Ellipse(R); @@ -3019,15 +3043,16 @@ begin Writeln(stdout,'Setting text'); system.flush(stdout); end; - Cnv.Textout(1,FH*2,Format('%d Skipped (%3.1f%%)',[Skipped,SR*100])); - A1:=(Pi*2*(failed/total)); - A2:=A1+(Pi*2*(Skipped/Total)); - AddPie(Ra,R.Top+Ra,Ra,A1,A2,ColYellow); + A1:=0; + A2:=A1+FractionAngle(Failed,Total); + cnv.font.FPColor:=colRed; + Cnv.Textout(1,FH*3,Format('%d Failed (%3.1f%%)',[Failed,FR*100])); + AddPie(Ra,R.Top+Ra,Ra,A1,A2,ColRed); cnv.font.FPColor:=colGreen; + Cnv.Textout(1,FH,Format('%d Passed (%3.1f%%)',[Total-Skipped-Failed,PR*100])); // Writeln('Palette size : ',Img.Palette.Count); A1:=A2; - A2:=A1+(Pi*2*((Total-(Skipped+Failed))/Total)); - Cnv.Textout(1,FH*3,Format('%d Passed (%3.1f%%',[Total-Skipped-Failed,PR*100])); + A2:=A1+FractionAngle(Total-(Skipped+Failed),Total); AddPie(Ra,R.Top+Ra,Ra,A1,A2,ColGreen); // Writeln('Palette size : ',Img.Palette.Count); // Writeln('All done'); diff --git a/avx512-0037785/tests/webtbf/tw24434.pp b/avx512-0037785/tests/webtbf/tw24434.pp new file mode 100644 index 0000000000..666655b0f8 --- /dev/null +++ b/avx512-0037785/tests/webtbf/tw24434.pp @@ -0,0 +1,13 @@ +{ %fail } +function f(s: string): string; +begin + f := '''' + s + ''''; +end; + +function f(s: string): integer; +begin + Val(s,f); +end; + +begin +end. diff --git a/avx512-0037785/tests/webtbf/tw37217.pp b/avx512-0037785/tests/webtbf/tw37217.pp new file mode 100644 index 0000000000..b2969f3353 --- /dev/null +++ b/avx512-0037785/tests/webtbf/tw37217.pp @@ -0,0 +1,12 @@ +{ %fail } +{$mode delphi} +type + TEagle = class + constructor Create<Y>(); + end; + +constructor TEagle.Create<Y>(); +begin +end; +begin +end. diff --git a/avx512-0037785/tests/webtbf/tw38287.pp b/avx512-0037785/tests/webtbf/tw38287.pp new file mode 100644 index 0000000000..6971257653 --- /dev/null +++ b/avx512-0037785/tests/webtbf/tw38287.pp @@ -0,0 +1,11 @@ +{$macro on} +var + a,b,s : real; + +begin + a:=1; + b:=2; +{$define sum:=a+b } +{$define b:=sum} { DON’T do this !!!} + s:=sum; { Will be infinitely recursively expanded... } +end. diff --git a/avx512-0037785/tests/webtbs/tw32139.pp b/avx512-0037785/tests/webtbs/tw32139.pp new file mode 100644 index 0000000000..ced0f60db1 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw32139.pp @@ -0,0 +1,11 @@ +{ %OPT=-Seh }
+program Test;
+
+{$HINTS ON}
+
+var
+ cur: Currency;
+begin
+ cur := 3.5;
+ cur := cur / 1.5;
+end.
diff --git a/avx512-0037785/tests/webtbs/tw34027.pp b/avx512-0037785/tests/webtbs/tw34027.pp new file mode 100644 index 0000000000..feacc2e199 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw34027.pp @@ -0,0 +1,27 @@ +uses + strings; + +type tz = record + name : pchar; + end; +const aa :array[0..2] of char = 'aa'#0; + +const testArrZ : array [0..4] of tz = ( + (name: @aa), { Ok } + (name: pchar(@aa)), { Ok } + (name: pchar(@aa)+1), + (name: pchar(@aa)+1+1), + (name: pchar(@aa)+1+1-1) + ); + +var b : pchar; + +begin + b:=pchar(@aa)+1; {Ok} + if strlen(testArrZ[2].name)<>1 then + halt(1); + if strlen(testArrZ[3].name)<>0 then + halt(2); + if strlen(testArrZ[4].name)<>1 then + halt(2); +end. diff --git a/avx512-0037785/tests/webtbs/tw37060.pp b/avx512-0037785/tests/webtbs/tw37060.pp index c167a50887..847c5ede4f 100644 --- a/avx512-0037785/tests/webtbs/tw37060.pp +++ b/avx512-0037785/tests/webtbs/tw37060.pp @@ -4,7 +4,7 @@ program fp37060; uses sockets, Classes, SysUtils; -procedure BuildBadAddrs4(out bad_addrs: TStringList); +procedure BuildBadAddrs4(var bad_addrs: TStringList); begin bad_addrs.Add('1.1.1.1.1'); // too many octets bad_addrs.Add('0xa.3.4.5'); //hex in octets @@ -32,7 +32,7 @@ begin bad_addrs.Add('&7.&5.30.4'); // octal end; -procedure BuildGoodAddrs4(out good_addrs: TStringList); +procedure BuildGoodAddrs4(var good_addrs: TStringList); begin good_addrs.Add('127.0.0.1|127.0.0.1'); good_addrs.Add('0.0.0.0|0.0.0.0'); @@ -40,7 +40,7 @@ begin good_addrs.Add('255.255.255.255|255.255.255.255'); end; -procedure BuildBadAddrs6(out bad_addrs: TStringList); +procedure BuildBadAddrs6(var bad_addrs: TStringList); begin // start with some obviously bad formats. bad_addrs.Add(''); @@ -193,7 +193,7 @@ begin bad_addrs.Add('127.0.0.2'); end; -procedure BuildGoodAddrs6(out addrlist: TStringList); +procedure BuildGoodAddrs6(var addrlist: TStringList); begin // Each str is two parts, separated by a pipe. The left part is the input // address to be parsed, and the right is the expected result of taking the diff --git a/avx512-0037785/tests/webtbs/tw38306.pp b/avx512-0037785/tests/webtbs/tw38306.pp new file mode 100644 index 0000000000..1fbcea7a38 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38306.pp @@ -0,0 +1,39 @@ +{ %OPT=-gh }
+{$mode objfpc}
+program gqueue_test;
+
+uses
+ gqueue;
+
+type
+ TIntQueue = specialize TQueue<Integer>;
+
+var
+ IntQueue: TIntQueue;
+ PushCnt: Integer;
+
+procedure Push2Pop1;
+var
+ i: Integer;
+begin
+ for i:= 0 to 1000000 do begin
+ IntQueue.Push(PushCnt);
+ inc(PushCnt);
+ IntQueue.Push(PushCnt);
+ inc(PushCnt);
+ IntQueue.Pop();
+ end;
+end;
+
+var
+ i: Integer;
+begin
+ try
+ IntQueue:= TIntQueue.Create;
+ Push2Pop1;
+ WriteLn('Ready');
+ finally
+ IntQueue.Free;
+ end;
+end.
+
diff --git a/avx512-0037785/tests/webtbs/tw38316.pp b/avx512-0037785/tests/webtbs/tw38316.pp new file mode 100644 index 0000000000..29cd58b0e7 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38316.pp @@ -0,0 +1,21 @@ +{ %opt=-gh } + +program project1; + +procedure P1(A: array of Integer); +begin +end; + +procedure P2(A: array of Integer); +begin + P1(A); +end; + +var + A: array [0..2] of Integer; + i: Integer; +begin + HaltOnNotReleased := true; + for i := 0 to 10 do + P2(A); +end. diff --git a/avx512-0037785/tests/webtbs/tw38337.pp b/avx512-0037785/tests/webtbs/tw38337.pp new file mode 100644 index 0000000000..7d461ddfa9 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38337.pp @@ -0,0 +1,20 @@ +program fs; + +{$mode objfpc}{$H+} + +function UTF8Length(const s: string): PtrInt; inline; +begin + Result:=9; +end; + + +var + v1: string; + s: shortstring; + i: Integer; +begin + v1 := '123456789'; + s := v1; + for i := 1 to UTF8Length(s)-8 do begin + end; +end. diff --git a/avx512-0037785/tests/webtbs/tw38339.pp b/avx512-0037785/tests/webtbs/tw38339.pp new file mode 100644 index 0000000000..e81db9c9da --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38339.pp @@ -0,0 +1,23 @@ +{%OPT=-O3 } +program test48086; +{$mode objfpc}{$H+} +function IsFontNameXLogicalFontDesc(const LongFontName: string): boolean; +var MinusCnt, p: integer; +begin + MinusCnt:=0; + for p:=1 to length(LongFontName) do + if LongFontName[p]='-' then inc(MinusCnt); + Result:=(MinusCnt=14); +end; +var +myfont:string; +begin + myfont:='Myfont--------------'; + if IsFontNameXLogicalFontDesc(myfont) then + writeln('NO ERROR') + else + begin + writeln('Error in count'); + halt(1); + end; +end. diff --git a/avx512-0037785/tests/webtbs/tw38351.pp b/avx512-0037785/tests/webtbs/tw38351.pp new file mode 100644 index 0000000000..d76d639b4c --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38351.pp @@ -0,0 +1,33 @@ +{$MODE OBJFPC}
+{$APPTYPE CONSOLE}
+
+uses Classes, BufStream, Sysutils;
+
+procedure TestBufferedFileStream;
+var
+ F: TStream;
+ pf: File;
+begin
+ Assign(pf,'tw38351.tmp');
+ Rewrite(pf,1);
+ Seek(pf,100);
+ Close(pf);
+ F := TBufferedFileStream.Create('tw38351.tmp', fmOpenRead);
+ try
+ Writeln(F.Position);
+ if F.Position<>0 then
+ halt(1);
+ Writeln(F.Seek(0, soBeginning)); // TFileStream = 0, TBufferedFileStream = -1
+ Writeln(F.Position);
+ if F.Position<>0 then
+ halt(1);
+ finally
+ F.Free;
+ DeleteFile('tw38351.tmp');
+ end;
+end;
+
+begin
+ TestBufferedFileStream;
+ writeln('ok');
+end.
diff --git a/avx512-0037785/tests/webtbs/tw38385.pp b/avx512-0037785/tests/webtbs/tw38385.pp new file mode 100644 index 0000000000..30a66965a2 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38385.pp @@ -0,0 +1,41 @@ +{ %norun } +Unit tw38385; + +{$mode objfpc}{$H+} + +Interface + +Uses + uw38385a, uw38385b, uw38385c; + +Type + + { TFoo } + + TFoo = Class(TInterfacedObject, uw38385a.IInterface1, uw38385b.IInterface1, uw38385c.IInterface1) + Procedure p1(); + Procedure p2(); + Procedure p3(); + End; + +Implementation + +{ TFoo } + +Procedure TFoo.p1(); +Begin + WriteLn('p1'); +End; + +Procedure TFoo.p2(); +Begin + WriteLn('p2'); +End; + +Procedure TFoo.p3(); +Begin + WriteLn('p3'); +End; + +End. + diff --git a/avx512-0037785/tests/webtbs/tw38390.pp b/avx512-0037785/tests/webtbs/tw38390.pp new file mode 100644 index 0000000000..11a2c523b0 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38390.pp @@ -0,0 +1,23 @@ +program tw38390; +{$MODE Delphi} +uses SysUtils; + +var + s: String; + x: UInt64; + +begin + s := '20000000000'; + x := UInt64.Parse(s); + WriteLn(x); + if x <> 20000000000 then + Halt(1); + UInt64.TryParse(s, x); + WriteLn(x); + if x <> 20000000000 then + Halt(2); + x := StrToQWord(s); + WriteLn(x); + if x <> 20000000000 then + Halt(3); +end. diff --git a/avx512-0037785/tests/webtbs/tw38412.pp b/avx512-0037785/tests/webtbs/tw38412.pp new file mode 100644 index 0000000000..dcfe911a99 --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38412.pp @@ -0,0 +1,10 @@ +{ %norun } +type + measure = (short := 1, long := 2); + generic bar<const x: measure> = object + public + const + myMeasure = ord(x); + end; +begin +end. diff --git a/avx512-0037785/tests/webtbs/tw38413.pp b/avx512-0037785/tests/webtbs/tw38413.pp new file mode 100644 index 0000000000..ccd5930eac --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38413.pp @@ -0,0 +1,12 @@ +var + arr : array[-1..140] of byte=(4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4); + index , value : byte; // unsigned byte - important +begin + index:=133; // positive value, which is treated as negative + value:=arr[index]; // wrong value! Memory access outside array + if value<>4 then + halt(1); + writeln('ok'); +end. diff --git a/avx512-0037785/tests/webtbs/tw38429.pp b/avx512-0037785/tests/webtbs/tw38429.pp new file mode 100644 index 0000000000..87e9c9913e --- /dev/null +++ b/avx512-0037785/tests/webtbs/tw38429.pp @@ -0,0 +1,61 @@ +program tw38429; + +{$mode objfpc}{$h+} + +uses + SysUtils, Variants, uw38429; + +var + v, d: Variant; + I: Integer = 42; +begin + Writeln('Test VarAsType'); + d := I; + try + v := VarAsType(d, varMyVar); + except + on e: exception do begin + WriteLn('cast ', VarTypeAsText(VarType(d)), ' to ',VarTypeAsText(varMyVar), + ' raises ', e.ClassName, ' with message: ', e.Message); + Halt(1); + end; + end; + WriteLn('now v is ', VarTypeAsText(VarType(v))); + VarClear(d); + try + d := VarAsType(v, varInteger); + except + on e: exception do begin + WriteLn('cast ', VarTypeAsText(VarType(v)), ' to ',VarTypeAsText(varInteger), + ' raises ', e.ClassName, ' with message: ', e.Message); + Halt(2); + end; + end; + WriteLn('now d is ', VarTypeAsText(VarType(d))); + + { also test VarCast from #20849 } + Writeln('Test VarCast'); + d := I; + try + VarCast(v, d, varMyVar); + except + on e: exception do begin + WriteLn('cast ', VarTypeAsText(VarType(d)), ' to ',VarTypeAsText(varMyVar), + ' raises ', e.ClassName, ' with message: ', e.Message); + Halt(3); + end; + end; + WriteLn('now v is ', VarTypeAsText(VarType(v))); + VarClear(d); + try + VarCast(d, v, varInteger); + except + on e: exception do begin + WriteLn('cast ', VarTypeAsText(VarType(v)), ' to ',VarTypeAsText(varInteger), + ' raises ', e.ClassName, ' with message: ', e.Message); + Halt(4); + end; + end; + WriteLn('now d is ', VarTypeAsText(VarType(d))); +end. + diff --git a/avx512-0037785/tests/webtbs/uw38385a.pp b/avx512-0037785/tests/webtbs/uw38385a.pp new file mode 100644 index 0000000000..41110fc8a8 --- /dev/null +++ b/avx512-0037785/tests/webtbs/uw38385a.pp @@ -0,0 +1,17 @@ +Unit uw38385a; + +{$mode objfpc}{$H+} + +Interface + +Type + IInterface1 = Interface(IInterface) + Procedure p1(); + End; + +Implementation + + + +End. + diff --git a/avx512-0037785/tests/webtbs/uw38385b.pp b/avx512-0037785/tests/webtbs/uw38385b.pp new file mode 100644 index 0000000000..a4b5d9eca7 --- /dev/null +++ b/avx512-0037785/tests/webtbs/uw38385b.pp @@ -0,0 +1,18 @@ +unit uw38385b; + +{$mode objfpc}{$H+} + +interface + +uses + uw38385a; + +type + IInterface1 = Interface(uw38385a.IInterface1) + Procedure p2(); + End; + +implementation + +end. + diff --git a/avx512-0037785/tests/webtbs/uw38385c.pp b/avx512-0037785/tests/webtbs/uw38385c.pp new file mode 100644 index 0000000000..069d50f7f4 --- /dev/null +++ b/avx512-0037785/tests/webtbs/uw38385c.pp @@ -0,0 +1,18 @@ +Unit uw38385c; + +{$mode objfpc}{$H+} + +Interface + +Uses + uw38385a; + +Type + IInterface1 = Interface(uw38385a.IInterface1) + Procedure p3(); + End; + +Implementation + +End. + diff --git a/avx512-0037785/tests/webtbs/uw38429.pp b/avx512-0037785/tests/webtbs/uw38429.pp new file mode 100644 index 0000000000..0ec87fb766 --- /dev/null +++ b/avx512-0037785/tests/webtbs/uw38429.pp @@ -0,0 +1,88 @@ +unit uw38429; + +{$mode objfpc}{$H+} +{$modeswitch advancedrecords} + +interface + +uses + SysUtils, Variants; + +type + TMyVar = packed record + VType: TVarType; + Dummy1: array[0..2] of Word; + Dummy2, + Dummy3: Pointer; + procedure Init; + end; + + { TMyVariant } + + TMyVariant = class(TInvokeableVariantType) + procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override; + procedure Clear(var V: TVarData); override; + procedure Cast(var Dest: TVarData; const Source: TVarData); override; + procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override; + end; + + function MyVarCreate: Variant; + + function varMyVar: TVarType; + +implementation + +var + MyVariant: TMyVariant; + +function MyVarCreate: Variant; +begin + VarClear(Result); + TMyVar(Result).Init; +end; + +function VarMyVar: TVarType; +begin + Result := MyVariant.VarType; +end; + +{ TMyVar } + +procedure TMyVar.Init; +begin + VType := VarMyVar; +end; + +{ TMyVariant } + +procedure TMyVariant.Copy(var Dest: TVarData; const Source: TVarData; + const Indirect: Boolean); +begin + Dest := Source; +end; + +procedure TMyVariant.Clear(var V: TVarData); +begin + TMyVar(v).VType := varEmpty; +end; + +procedure TMyVariant.Cast(var Dest: TVarData; const Source: TVarData); +begin + WriteLn('TMyVariant.Cast'); + VarClear(Variant(Dest)); + TMyVar(Dest).Init; +end; + +procedure TMyVariant.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); +begin + WriteLn('TMyVariant.CastTo'); + VarClear(Variant(Dest)); + TVarData(Dest).VType := aVarType; +end; + +initialization + MyVariant := TMyVariant.Create; +finalization + MyVariant.Free; +end. + diff --git a/avx512-0037785/utils/fpdoc/dglobals.pp b/avx512-0037785/utils/fpdoc/dglobals.pp index 2cfed6aed8..c2bd23dd97 100644 --- a/avx512-0037785/utils/fpdoc/dglobals.pp +++ b/avx512-0037785/utils/fpdoc/dglobals.pp @@ -33,203 +33,6 @@ Var LEOL : Integer; modir : string; -resourcestring - // Output strings - SDocPackageTitle = 'Reference for package ''%s'''; - SDocPackageMenuTitle = 'Package ''%s'''; - SDocPackageLinkTitle = 'Package'; - SDocPrograms = 'Programs'; - SDocUnits = 'Units'; - SDocUnitTitle = 'Reference for unit ''%s'''; - SDocUnitMenuTitle = 'Unit ''%s'''; - SDocInheritanceHierarchy = 'Inheritance Hierarchy'; - SDocInterfaceSection = 'Interface section'; - SDocImplementationSection = 'Implementation section'; - SDocUsedUnits = 'Used units'; - SDocUsedUnitsByUnitXY = 'Used units by unit ''%s'''; - SDocConstsTypesVars = 'Constants, types and variables'; - SDocResStrings = 'Resource strings'; - SDocTypes = 'Types'; - SDocType = 'Type'; - SDocConstants = 'Constants'; - SDocConstant = 'Constant'; - SDocClasses = 'Classes'; - SDocClass = 'Class'; - SDocProceduresAndFunctions = 'Procedures and functions'; - SDocProcedureOrFunction = 'Procedure/function'; - SDocVariables = 'Variables'; - SDocVariable = 'Variable'; - SDocIdentifierIndex = 'Index'; - SDocPackageClassHierarchy = 'Class hierarchy'; - SDocModuleIndex = 'Index of all identifiers in unit ''%s'''; - SDocPackageIndex = 'Index of all identifiers in package ''%s'''; - SDocUnitOverview = 'Overview of unit ''%s'''; - SDocOverview = 'Overview'; - SDocSearch = 'Search'; - SDocDeclaration = 'Declaration'; - SDocDescription = 'Description'; - SDocErrors = 'Errors'; - SDocVersion = 'Version info'; - SDocSeeAlso = 'See also'; - SDocExample = 'Example'; - SDocArguments = 'Arguments'; - SDocFunctionResult = 'Function result'; - SDocRemark = 'Remark: '; - SDocMethodOverview = 'Method overview'; - SDocPropertyOverview = 'Property overview'; - SDocEventOverview = 'Event overview'; - SDocInterfacesOverview = 'Interfaces overview'; - SDocInterface = 'Interfaces'; - SDocPage = 'Page'; - SDocMember = 'Member'; - SDocMembers = 'Members'; - SDocField = 'Field'; - SDocMethod = 'Method'; - SDocProperty = 'Property'; - SDocAccess = 'Access'; - SDocInheritance = 'Inheritance'; - SDocProperties = 'Properties'; - SDocMethods = 'Methods'; - SDocEvents = 'Events'; - SDocByName = 'by Name'; - SDocByInheritance = 'By inheritance'; - SDocValue = 'Value'; - SDocExplanation = 'Explanation'; - SDocProcedure = 'Procedure'; - SDocValuesForEnum = 'Enumeration values for type %s'; - SDocSourcePosition = 'Source position: %s line %d'; - SDocSynopsis = 'Synopsis'; - SDocVisibility = 'Visibility'; - SDocOpaque = 'Opaque type'; - SDocDateGenerated = 'Documentation generated on: %s'; - // The next line requires leading/trailing space due to XML comment layout: - SDocGeneratedByComment = ' Generated using FPDoc - (c) 2000-2012 FPC contributors and Sebastian Guenther, sg@freepascal.org '; - SDocNotes = 'Notes'; - SDocName = 'Name'; - SDocType_s = 'Type(s)'; - SDocTopic = 'Topic'; - SDocNoneAVailable = 'No members available'; - - // Topics - SDocRelatedTopics = 'Related topics'; - SDocUp = 'Up'; - SDocNext = 'Next'; - SDocPrevious = 'Previous'; - - // Various backend constants - SDocChapter = 'Chapter'; - SDocSection = 'Section'; - SDocSubSection = 'Subsection'; - SDocTable = 'Table'; - SDocListing = 'Listing'; - - // Man page usage - SManUsageManSection = 'Use ASection as the man page section'; - SManUsageNoUnitPrefix = 'Do not prefix man pages with unit name.'; - SManUsageWriterDescr = 'UNIX man page output.'; - SManUsagePackageDescription = 'Use descr as the description of man pages'; - - // HTML usage - SHTMLUsageFooter = 'Append xhtml (@filename reads from file) as footer to html page'; - SHTMLUsageNavigator = 'Append xhtml (@filename reads from file) in navigator bar'; - SHTMLUsageHeader = 'Append xhtml (@filename reads from file) as header to html page below navigation bar'; - SHTMLUsageFooterDate = 'Append footer with date. fmt is Optional format for FormatDateTime'; - SHTMLUsageCharset = 'Set the HTML character set'; - SHTMLHtmlSearch = 'Add search page with given name to the menu bar'; - SHTMLIndexColcount = 'Use N columns in the identifier index pages'; - SHTMLImageUrl = 'Prefix image URLs with url'; - SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css'; - - // CHM usage - SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.'; - SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.'; - SCHMUsageDefPage = 'Set the "Home" page relative to where it lives in the chm. i.e. "/index.html"'; - SCHMUsageOtrFiles= 'A txt file containing a list of files to be added relative to the working directory.'; - SCHMUsageCSSFile = 'Filename of a .css file to be included in the chm.'; - SCHMUsageAutoTOC = 'Automatically generate a Table of Contents. Ignores --toc-file'; - SCHMUsageAutoIDX = 'Automatically generate an Index. Ignores --index-file'; - SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*'; - SCHMUsageChmTitle= 'Title of the chm. Defaults to the value from --package'; - - // MarkDown usage - SMDUsageFooter = 'Append markdown (@filename reads from file) as footer to every markdown page'; - SMDUsageHeader = 'Prepend markdown (@filename reads from file) as header to every markdown page'; - SMDIndexColcount = 'Use N columns in the identifier index pages'; - SMDImageUrl = 'Prefix image URLs with url'; - SMDTheme = 'Use name as theme name'; - SMDNavigation = 'Use scheme for navigation tree, here scheme is one of:'; - SMDNavSubtree = ' UnitSubTree : put all units in a sub tree of a Units node'; - SMDNavTree = ' UnitTree : put every units as a node on the same level as packages node'; - - SXMLUsageFlatStructure = 'Use a flat output structure of XML files and directories'; - SXMLUsageSource = 'Include source file and line info in generated XML'; - - // Linear usage - SLinearUsageDupLinkedDocsP1 = 'Duplicate linked element documentation in'; - SLinearUsageDupLinkedDocsP2 = 'descendant classes.'; - - STitle = 'FPDoc - Free Pascal Documentation Tool'; - SVersion = 'Version %s [%s]'; - SCopyright1 = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org'; - SCopyright2 = '(c) 2005 - 2021 various FPC contributors'; - - SCmdLineHelp = 'Usage: %s [options]'; - SUsageOption008 = '--base-descr-dir=DIR prefix all description files with this directory'; - SUsageOption009 = '--base-input-dir=DIR prefix all input files with this directory'; - SUsageOption010 = '--content Create content file for package cross-references'; - SUsageOption020 = '--cputarget=value Set the target CPU for the scanner.'; - SUsageOption030 = '--descr=file use file as description file, e.g.: '; - SUsageOption035 = ' --descr=c:\WIP\myzipperdoc.xml'; - SUsageOption040 = ' This option is allowed more than once'; - SUsageOption050 = '--descr-dir=Dir Add All XML files in Dir to list of description files'; - SUsageOption060 = '--format=fmt Select output format.'; - SUsageOption070 = '--help Show this help.'; - SUsageOption080 = '--hide-protected Do not show protected methods in overview'; - SUsageOption090 = '--import=file Import content file for package cross-references'; - SUsageOption100 = '--input=cmd use cmd as input for the parser, e.g.:'; - SUsageOption110 = ' --input=C:\fpc\packages\paszlib\src\zipper.pp'; - SUsageOption120 = ' At least one input option is required.'; - SUsageOption130 = '--input-dir=Dir Add All *.pp and *.pas files in Dir to list of input files'; - SUsageOption140 = '--lang=lng Select output language.'; - SUsageOption145 = '--macro=name=value Define a macro to preprocess the project file with.'; - SUsageOption150 = '--ostarget=value Set the target OS for the scanner.'; - SUsageOption160 = '--output=name use name as the output name.'; - SUsageOption170 = ' Each backend interprets this as needed.'; - SUsageOption180 = '--package=name Set the package name for which to create output,'; - SUsageOption190 = ' e.g. --package=fcl'; - SUsageOption200 = '--project=file Use file as project file'; - SUsageOption210 = '--show-private Show private methods.'; - SUsageOption215 = '--stop-on-parser-error'; - SUsageOption215A = ' Stop when a parser error occurs. Default is to ignore parser errors.'; - SUsageOption220 = '--warn-no-node Warn if no documentation node was found.'; - SUsageOption230 = '--mo-dir=dir Set directory where language files reside to dir'; - SUsageOption240 = '--parse-impl (Experimental) try to parse implementation too'; - SUsageOption250 = '--dont-trim Do not trim XML contents. Useful for preserving'; - SUsageOption260 = ' formatting inside e.g <pre> tags'; - SUsageOption270 = '--write-project=file'; - SUsageOption280 = ' Do not write documentation, create project file instead'; - SUsageOption290 = '--verbose Write more information on the screen'; - SUsageOption300 = '--dry-run Only parse sources and XML, do not create output'; - SUsageOption310 = '--write-project=file'; - SUsageOption320 = ' Write all command-line options to a project file'; - SUsageSubNames = 'Use the file subnames instead the indexes as postfixes'; - - SUsageFormats = 'The following output formats are supported by this fpdoc:'; - SUsageBackendHelp = 'Specify an output format, combined with --help to get more help for this backend.'; - SUsageFormatSpecific = 'Output format "%s" supports the following options:'; - SCmdLineErrInvalidMacro = 'Macro needs to be in the form name=value'; - - SCmdLineInvalidOption = 'Ignoring unknown option "%s"'; - SCmdLineInvalidFormat = 'Invalid format "%s" specified'; - SCmdLineOutputOptionMissing = 'Need an output filename, please specify one with --output=<filename>'; - SWritingPages = 'Writing %d pages...'; - SNeedPackageName = 'No package name specified. Please specify one using the --package option.'; - SAvailablePackages = 'Available packages: '; - SDone = 'Done.'; - SErrCouldNotCreateOutputDir = 'Could not create output directory "%s"'; - SErrCouldNotCreateFile = 'Could not create file "%s": %s'; - SSeeURL = '(See %s)'; // For linear text writers. - SParsingUsedUnit = 'Parsing used unit "%s" with commandLine "%s"'; Const SVisibility: array[TPasMemberVisibility] of string = @@ -335,7 +138,7 @@ type // The main FPDoc engine - TFPDocLogLevel = (dleWarnNoNode); + TFPDocLogLevel = (dleWarnNoNode, dleWarnUsedFile, dleDocumentationEmpty, dleXCT); TFPDocLogLevels = set of TFPDocLogLevel; TOnParseUnitEvent = Procedure (Sender : TObject; Const AUnitName : String; Out AInputFile,OSTarget,CPUTarget : String) of Object; @@ -364,8 +167,7 @@ type HasContentFile: Boolean; HidePrivate: Boolean; // Hide private class members in output? HideProtected: Boolean; // Hide protected class members in output? - WarnNoNode : Boolean; // Warn if no description node found for element. - + FalbackSeeAlsoLinks: Boolean; // Simplify SeeAlso Links constructor Create; destructor Destroy; override; procedure SetPackageName(const APackageName: String); @@ -378,7 +180,7 @@ type AParent: TPasElement; AVisibility: TPasMemberVisibility; const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override; - function FindInModule(const AName: String ; AModule: TPasModule): TPasElement; + function FindElement(const AName: String ; AModule: TPasModule): TPasElement; overload; function FindElement(const AName: String): TPasElement; override; function FindModule(const AName: String): TPasModule; override; Function HintsToStr(Hints : TPasMemberHints) : String; @@ -386,6 +188,7 @@ type // Link tree support procedure AddLink(const APathName, ALinkTo: String); function FindAbsoluteLink(const AName: String): String; + // resolve link inside actual AModule and AModule.Parent = APackage function ResolveLink(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String; function FindLinkedNode(ANode: TDocNode): TDocNode; Function ShowElement(El : TPasElement) : Boolean; inline; @@ -411,7 +214,9 @@ type procedure TranslateDocStrings(const Lang: String); +{$IFDEF EXCEPTION_STACK} function DumpExceptionCallStack(E: Exception):String; +{$ENDIF} Function IsLinkNode(Node : TDomNode) : Boolean; Function IsExampleNode(Example : TDomNode) : Boolean; @@ -422,7 +227,7 @@ Function IsLinkAbsolute(ALink: String): boolean; implementation -uses Gettext, XMLRead; +uses Gettext, XMLRead, fpdocstrs; const AbsoluteLinkPrefixes : array[0..2] of string = ('/', 'http://', 'ms-its:'); @@ -670,8 +475,11 @@ destructor TFPDocEngine.Destroy; var i: Integer; begin + if FPackages.Count > 0 then for i := 0 to FPackages.Count - 1 do - TPasPackage(FPackages[i]).Release{$IFDEF CheckPasTreeRefCount}('TFPDocEngine.Destroy'){$ENDIF}; + TPasPackage(FPackages[i]).Release{$IFDEF CheckPasTreeRefCount}('TFPDocEngine.Destroy'){$ENDIF} + else + FreeAndNil(FPackages); FreeAndNil(FRootDocNode); FreeAndNil(FRootLinkNode); FreeAndNil(DescrDocNames); @@ -910,7 +718,7 @@ var end; end else - if cls<>result then + if (dleXCT in FDocLogLevels) and (cls<>result) then DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]); end; @@ -970,7 +778,7 @@ var if alname<>'' then // the class//interface we refered to is an alias begin // writeln('Found alias pair ',clname,' = ',alname); - if not assigned(CreateAliasType(alname,clname,cls,cls2)) then + if (dleXCT in FDocLogLevels) and not assigned(CreateAliasType(alname,clname,cls,cls2)) then DoLog('Warning: creating alias %s for %s failed!',[alname,clname]); end else @@ -1217,7 +1025,7 @@ begin Result.SourceLinenumber := ASourceLinenumber; end; -function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule +function TFPDocEngine.FindElement ( const AName: String; AModule: TPasModule ) : TPasElement; var l: TFPList; @@ -1244,14 +1052,14 @@ var i: Integer; Module: TPasElement; begin - Result := FindInModule( AName, CurModule ); + Result := FindElement( AName, CurModule ); if not Assigned(Result) and assigned (CurModule.InterfaceSection) then for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do begin Module := TPasElement(CurModule.InterfaceSection.UsesList[i]); if Module.ClassType.InheritsFrom(TPasModule) then begin - Result := FindInModule(AName, TPasModule(Module)); + Result := FindElement(AName, TPasModule(Module)); if Assigned(Result) then exit; end; @@ -1264,6 +1072,7 @@ function TFPDocEngine.FindModule(const AName: String): TPasModule; var i: Integer; begin + if not Assigned(APackage) then Exit; for i := 0 to APackage.Modules.Count - 1 do begin Result := TPasModule(APackage.Modules[i]); @@ -1279,7 +1088,7 @@ var begin Result := FindInPackage(Package); - if not Assigned(Result) then + if not Assigned(Result) and (FPackages.Count > 0) then for i := FPackages.Count - 1 downto 0 do begin if TPasPackage(FPackages[i]) = Package then @@ -1319,11 +1128,12 @@ Var M : TPasModule; begin - DoLog(SParsingUsedUnit,[AName,AInputLine]); + if dleWarnUsedFile in FDocLogLevels then + DoLog(SParsingUsedUnit,[AName,AInputLine]); M:=CurModule; CurModule:=Nil; try - ParseSource(Self,AInputLine,AOSTarget,ACPUTarget,[poUseStreams,poSkipDefaultDefs]); + ParseSource(Self,AInputLine,AOSTarget,ACPUTarget,[poUseStreams]); //[poSkipDefaultDefs]; Result:=CurModule; finally CurModule:=M; @@ -1382,7 +1192,6 @@ end; function TFPDocEngine.ResolveLink(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String; var i: Integer; - begin { if Assigned(AModule) then @@ -1393,14 +1202,18 @@ begin if (ALinkDest='') then Exit(''); if (ALinkDest[1] = '#') then + // Link has full path Result := FindAbsoluteLink(ALinkDest) else if (AModule=Nil) then + // Trying to add package name only Result:= FindAbsoluteLink(RootLinkNode.FirstChild.Name+'.'+ALinkDest) else begin - if Pos(AModule.Name,ALinkDest) = 1 then + if Pos(LowerCase(AModule.Name)+'.',LowerCase(ALinkDest)) = 1 then + // fix ERROR - Link starts from name of module Result := ResolveLink(AModule, AModule.packagename + '.' + ALinkDest, Strict) else + // Link should be a first level inside of module Result := ResolveLink(AModule, AModule.PathName + '.' + ALinkDest, Strict); if (Result='') then begin @@ -1411,12 +1224,17 @@ begin end; // Match on parent : class/enumerated/record/module if (Result='') and not strict then + begin + // TODO: I didn't see a calling this code at entire lcl package + // Writeln('INFO UnStrinct(): ' + ALinkDest); for i := Length(ALinkDest) downto 1 do if ALinkDest[i] = '.' then begin Result := ResolveLink(AModule, Copy(ALinkDest, 1, i - 1), Strict); + //if Result <> '' then Writeln('INFO LinkResolved UnStrinct(): '+Result); exit; end; + end; end; procedure ReadXMLFileALT(OUT ADoc:TXMLDocument;const AFileName:ansistring); @@ -1590,7 +1408,7 @@ begin if aElement.CustomData=Nil then aElement.CustomData:=Result; end - else if WarnNoNode and + else if (dleWarnNoNode in FDocLogLevels) and (Length(AElement.PathName)>0) and (AElement.PathName[1]='#') then DoLog(Format('No documentation node found for identifier : %s',[AElement.PathName])); @@ -1791,6 +1609,7 @@ begin end; end; +{$IFDEF EXCEPTION_STACK} function DumpExceptionCallStack(E: Exception):String; var I: Integer; @@ -1807,6 +1626,7 @@ begin for I := 0 to ExceptFrameCount - 1 do Result := Result + LineEnding + BackTraceStrFunc(Frames[I]); end; +{$ENDIF} initialization LEOL:=Length(LineEnding); diff --git a/avx512-0037785/utils/fpdoc/dw_basehtml.pp b/avx512-0037785/utils/fpdoc/dw_basehtml.pp index c0a82aae25..6dc246a4e9 100644 --- a/avx512-0037785/utils/fpdoc/dw_basehtml.pp +++ b/avx512-0037785/utils/fpdoc/dw_basehtml.pp @@ -158,7 +158,7 @@ Function FixHTMLpath(S : String) : STring; implementation -uses xmlread, sysutils, sh_pas; +uses fpdocstrs, xmlread, sysutils, sh_pas; Function FixHTMLpath(S : String) : STring; @@ -428,6 +428,7 @@ begin else N:='?'; DoLog(SErrUnknownLinkID, [s,n,a]); + LinkUnresolvedInc(); PushOutputNode(CreateEl(CurOutputNode, 'b')); end else PushOutputNode(CreateLink(CurOutputNode, s)); @@ -797,7 +798,10 @@ begin TREl:=CreateTR(TableEl); ParaEl:=CreatePara(CreateTD_vtop(TREl)); l:=El['id']; - s:= ResolveLinkID(UTF8ENcode(l)); + if Assigned(Engine) and Engine.FalbackSeeAlsoLinks then + s:= ResolveLinkIDUnStrict(UTF8ENcode(l)) + else + s:= ResolveLinkID(UTF8ENcode(l)); if Length(s)=0 then begin if assigned(module) then @@ -806,10 +810,11 @@ begin s:='?'; if l='' then l:='<empty>'; if Assigned(AElement) then - N:=UTF8Decode(AElement.Name) + N:=UTF8Decode(AElement.PathName) else N:='?'; DoLog(SErrUnknownLinkID, [s,N,l]); + LinkUnresolvedInc(); NewEl := CreateEl(ParaEl,'b') end else @@ -1007,7 +1012,7 @@ begin break; ThisPackage := ThisPackage.NextSibling; end; - if Length(s) = 0 then + if (Length(s) = 0) and Assigned(Module) then begin { Okay, then we have to try all imported units of the current module } UnitList := Module.InterfaceSection.UsesList; @@ -1033,6 +1038,8 @@ begin end else if Element is TPasEnumValue then s := ResolveLinkID(Element.Parent.PathName) + else if Element is TPasAliasType then + s := ResolveLinkID(TPasAliasType(Element).DestType.PathName) else s := ResolveLinkID(Element.PathName); @@ -1044,7 +1051,10 @@ begin else begin Result := nil; - AppendText(Parent, Element.Name); // unresolved items + if Element is TPasAliasType then + AppendText(Parent, TPasAliasType(Element).DestType.Name) + else + AppendText(Parent, Element.Name); // unresolved items end; end; diff --git a/avx512-0037785/utils/fpdoc/dw_basemd.pp b/avx512-0037785/utils/fpdoc/dw_basemd.pp index 6ab3e04c39..28e323dfae 100644 --- a/avx512-0037785/utils/fpdoc/dw_basemd.pp +++ b/avx512-0037785/utils/fpdoc/dw_basemd.pp @@ -184,15 +184,8 @@ Type implementation -resourcestring - SErrCannotChangeIndentSizeWhenIndented = 'Cannot change indent size while text is indented.'; - SErrIndentMismatch = 'Indent mismatch: trying to undent when current indent too small'; - SErrNotInList = 'Not in list'; - SErrPopListStack = 'Pop list stack list type mismatch'; - SErrMinListStack = 'Min list stack reached'; - SErrMaxListStack = 'Max list stack reached'; - SErrMinIndentStack = 'Min indent stack reached'; - SErrMaxIndentStack = 'Max indent stack reached'; +uses fpdocstrs; + procedure TBaseMarkdownWriter.SetIndentSize(AValue: Byte); begin @@ -558,6 +551,7 @@ begin else N:='?'; DoLog(SErrUnknownLinkID, [s,n,a]); + LinkUnresolvedInc(); end end; diff --git a/avx512-0037785/utils/fpdoc/dw_chm.pp b/avx512-0037785/utils/fpdoc/dw_chm.pp index 30195d5b07..31fb05edd8 100644 --- a/avx512-0037785/utils/fpdoc/dw_chm.pp +++ b/avx512-0037785/utils/fpdoc/dw_chm.pp @@ -1,5 +1,8 @@ unit dw_chm; +{$mode objfpc} +{$h+} + interface uses Classes, DOM, @@ -40,7 +43,7 @@ type FAutoIndex: Boolean; FOtherFiles: String; procedure ProcessOptions; - function ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString; + function ResolveLinkIDAbs(const Name: String): DOMString; function RetrieveOtherFiles(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean; procedure LastFileAdded(Sender: TObject); @@ -50,10 +53,10 @@ type APasEl: TPasElement; Prefix:String); procedure GenerateTOC; procedure GenerateIndex; + protected + procedure DoWriteDocumentation; override; public - procedure WriteDoc; override; function CreateAllocator: TFileAllocator; override; - function InterPretOption(const Cmd,Arg : String): boolean; override; class procedure Usage(List: TStrings); override; @@ -63,7 +66,7 @@ type implementation -uses SysUtils, HTMWrite, dw_basehtml; +uses fpdocstrs, SysUtils, HTMWrite, dw_basehtml; { TCHmFileNameAllocator } @@ -72,6 +75,7 @@ var n,s: String; i: Integer; excl: Boolean; //search + MElement: TPasElement; begin Result:=''; excl := False; @@ -120,7 +124,9 @@ begin excl := (ASubindex > 0); end; // cut off Package Name - AElement:= AElement.GetModule; + MElement:= AElement.GetModule; + if Assigned(MElement) then + AElement:= MElement; Result := Copy(Result, Length(AElement.Parent.Name) + 2, MaxInt); // to skip dots in unit name i := Length(AElement.Name); @@ -163,7 +169,7 @@ end; { TCHMHTMLWriter } -function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString; +function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String): DOMString; begin Result:=UTF8Decode(FixHTMLpath(Engine.ResolveLink(Module,Name, True))); @@ -341,8 +347,10 @@ begin Continue; ObjUnitItem := ObjByUnitItem.Children.NewItem; ObjUnitItem.Text := AModule.Name; + ObjUnitItem.addLocal(FixHTMLpath(Allocator.GetFilename(AModule, ClassesSubindex))); RoutinesUnitItem := RoutinesByUnitItem.Children.NewItem; RoutinesUnitItem.Text := AModule.Name; + RoutinesUnitItem.addLocal(FixHTMLpath(Allocator.GetFilename(AModule, ProcsSubindex))); for j := 0 to AModule.InterfaceSection.Classes.Count-1 do begin Element := TPasClassType(AModule.InterfaceSection.Classes[j]); @@ -621,7 +629,7 @@ begin DoLog('Generating Index Done'); end; -procedure TCHMHTMLWriter.WriteDoc; +procedure TCHMHTMLWriter.DoWriteDocumentation; var i: Integer; PageDoc: TXMLDocument; @@ -629,8 +637,6 @@ var IFileName,FileName: String; FilePath: String; begin - FAllocator:=CreateAllocator; - FAllocator.SubPageNames:= SubPageNames; AllocatePages; DoLog(SWritingPages, [PageCount]); diff --git a/avx512-0037785/utils/fpdoc/dw_dxml.pp b/avx512-0037785/utils/fpdoc/dw_dxml.pp index 330faa986a..9f3ef98692 100644 --- a/avx512-0037785/utils/fpdoc/dw_dxml.pp +++ b/avx512-0037785/utils/fpdoc/dw_dxml.pp @@ -12,7 +12,7 @@ type { TXMLWriter } TDXMLWriter = class(TFPDocWriter) - procedure WriteDoc; override; + procedure DoWriteDocumentation; override; end; { TDocumentation } @@ -472,7 +472,7 @@ end; { TXMLWriter } -procedure TDXMLWriter.WriteDoc; +procedure TDXMLWriter.DoWriteDocumentation; var i: integer; begin diff --git a/avx512-0037785/utils/fpdoc/dw_html.pp b/avx512-0037785/utils/fpdoc/dw_html.pp index 298114f9f7..b8afe2be7d 100644 --- a/avx512-0037785/utils/fpdoc/dw_html.pp +++ b/avx512-0037785/utils/fpdoc/dw_html.pp @@ -67,7 +67,6 @@ type procedure FinishElementPage(AElement: TPasElement);virtual; procedure AppendFooter;virtual; - procedure AppendClassMemberListLink(aClass: TPasClassType; ParaEl: TDomElement; AListSubpageIndex: Integer; const AText: DOMString);virtual; procedure CreateClassMainPage(aClass: TPasClassType);virtual; procedure CreateClassInheritanceSubpage(aClass: TPasClassType; AFilter: TMemberFilter);virtual; @@ -97,6 +96,9 @@ type procedure CreateProcPageBody(AProc: TPasProcedureBase); Procedure CreateTopicLinks(Node : TDocNode; PasElement : TPasElement); procedure AppendTypeDecl(AType: TPasType; TableEl, CodeEl: TDomElement); + // Main documentation process + Procedure DoWriteDocumentation; override; + Property HeaderHTML : TStringStream Read FHeaderHTML; Property NavigatorHTML : TStringStream read FNavigatorHTML; Property FooterHTML : TStringStream read FFooterHTML; @@ -104,7 +106,7 @@ type Property HeadElement : TDomElement Read FHeadElement; Property TitleElement: TDOMElement Read FTitleElement; public - // Creating all module hierarchy classes is here !!!! + // Creating all module hierarchy classes happens here ! constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; // Overrides Class Function FileNameExtension : String; override; @@ -112,7 +114,6 @@ type Class procedure SplitImport(var AFilename, ALinkPrefix: String); override; Function InterPretOption(Const Cmd,Arg : String) : boolean; override; - Procedure WriteDoc; override; // Single-page generation function CreateHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument; virtual; @@ -129,7 +130,7 @@ type implementation -uses SysUtils, HTMWrite, fpdocclasstree; +uses fpdocstrs, SysUtils, HTMWrite, fpdocclasstree; {$i css.inc} {$i plusimage.inc} @@ -207,7 +208,8 @@ begin PageDoc.Free; end; -procedure THTMLWriter.WriteDoc; +procedure THTMLWriter.DoWriteDocumentation; + begin Inherited; @@ -338,6 +340,8 @@ function THTMLWriter.AppendProcType(CodeEl, TableEl: TDOMElement; var i: Integer; Arg: TPasArgument; + S : String; + begin if Element.Args.Count > 0 then begin @@ -347,12 +351,9 @@ begin begin Arg := TPasArgument(Element.Args[i]); CodeEl := CreateIndentedCodeEl(Indent + 2); - - case Arg.Access of - argConst: AppendKw(CodeEl, 'const '); - argVar: AppendKw(CodeEl, 'var '); - argOut: AppendKw(CodeEl, 'out '); - end; + S:=AccessNames[Arg.Access]; + if (S<>'') then + AppendKw(CodeEl,S); AppendText(CodeEl, Arg.Name); if Assigned(Arg.ArgType) then begin @@ -1743,7 +1744,6 @@ end; procedure THTMLWriter.CreateClassMainPage(aClass : TPasClassType); procedure AppendGenericTypes(CodeEl : TDomElement; AList : TFPList; isSpecialize : Boolean); - Var I : integer; begin @@ -1758,12 +1758,35 @@ procedure THTMLWriter.CreateClassMainPage(aClass : TPasClassType); AppendSym(CodeEl, '>'); end; + procedure AppendGeneric(ACodeEl : TDomElement ; AGenericObject: TPasClassType); + begin + if AGenericObject.GenericTemplateTypes.Count>0 then + begin + AppendKw(ACodeEl, ' generic '); + AppendText(ACodeEl, ' ' + UTF8Decode(AGenericObject.Name) + ' '); + AppendGenericTypes(ACodeEl,AGenericObject.GenericTemplateTypes,false); + end; + end; + + procedure AppendInterfaceInfo(ACodeEl : TDomElement ; AThisClass: TPasClassType); + var + i:Integer; + ThisInterface:TPasClassType; + begin + if Assigned(AThisClass) and (AThisClass.Interfaces.count>0) then + begin + for i:=0 to AThisClass.interfaces.count-1 do + begin + ThisInterface:=TPasClassType(AThisClass.Interfaces[i]); + AppendText(ACodeEl,','); + AppendHyperlink(ACodeEl, ThisInterface); + end; + end; + end; var ParaEl,TableEl, TREl, TDEl, CodeEl: TDOMElement; - i: Integer; - ThisInterface, - ThisClass: TPasClassType; + ThisClass, PrevClass: TPasType; ThisTreeNode: TPasElementNode; begin //WriteLn('@ClassPageBody.CreateMainPage Class=', AClass.Name); @@ -1785,41 +1808,55 @@ begin TDEl := CreateTD(TREl); CodeEl := CreateCode(CreatePara(TDEl)); AppendKw(CodeEl, 'type'); + + if not Assigned(AClass.GenericTemplateTypes) then + Dolog('ERROR generic init: %s', [AClass.name]); if AClass.GenericTemplateTypes.Count>0 then - AppendKw(CodeEl, ' generic '); - AppendText(CodeEl, ' ' + UTF8Decode(AClass.Name) + ' '); - if AClass.GenericTemplateTypes.Count>0 then - AppendGenericTypes(CodeEl,AClass.GenericTemplateTypes,false); + AppendGeneric(CodeEl, AClass) + else + AppendText(CodeEl, ' ' + UTF8Decode(AClass.Name) + ' '); + AppendSym(CodeEl, '='); AppendText(CodeEl, ' '); AppendKw(CodeEl, UTF8Decode(ObjKindNames[AClass.ObjKind])); + // Now we are using only TreeClass for show inheritance + + ThisClass := AClass; ThisTreeNode := Nil; + if AClass.ObjKind = okInterface then + ThisTreeNode := TreeInterface.GetPasElNode(AClass) + else + ThisTreeNode := TreeClass.GetPasElNode(AClass); + if not Assigned(ThisTreeNode) Then + DoLog('ERROR Tree Class information: '+ThisClass.PathName); + if Assigned(AClass.AncestorType) then begin AppendSym(CodeEl, '('); - AppendHyperlink(CodeEl, AClass.AncestorType); - if AClass.Interfaces.count>0 Then - begin - for i:=0 to AClass.interfaces.count-1 do - begin - AppendSym(CodeEl, ', '); - AppendHyperlink(CodeEl,TPasClassType(AClass.Interfaces[i])); - end; - end; + // Show parent class information + if (AClass.AncestorType is TPasSpecializeType) then + begin + AppendText(CodeEl, 'specialize '); + AppendHyperlink(CodeEl, TPasSpecializeType(AClass.AncestorType).DestType); + AppendText(CodeEl, '<,>'); + end + else + begin + AppendHyperlink(CodeEl, AClass.AncestorType); + AppendInterfaceInfo(CodeEl, AClass); + end; AppendSym(CodeEl, ')'); end; + // Class members CreateMemberDeclarations(AClass, AClass.Members,TableEl, not AClass.IsShortDefinition); AppendText(CreateH2(ContentElement), UTF8Decode(SDocInheritance)); TableEl := CreateTable(ContentElement); - // Now we are using only TreeClass for show inheritance + // Process tree class information + // First tree class link is to This class + PrevClass:= nil; - ThisClass := AClass; ThisTreeNode := Nil; - if AClass.ObjKind = okInterface then - ThisTreeNode := TreeInterface.GetPasElNode(AClass) - else - ThisTreeNode := TreeClass.GetPasElNode(AClass); while True do begin TREl := CreateTR(TableEl); @@ -1828,23 +1865,10 @@ begin CodeEl := CreateCode(CreatePara(TDEl)); // Show class item - if Assigned(ThisClass) Then - AppendHyperlink(CodeEl, ThisClass); - //else - // AppendHyperlink(CodeEl, ThisTreeNode); - // Show links to class interfaces - if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then - begin - for i:=0 to ThisClass.interfaces.count-1 do - begin - ThisInterface:=TPasClassType(ThisClass.Interfaces[i]); - AppendText(CodeEl,','); - AppendHyperlink(CodeEl, ThisInterface); - end; - end; - // short class description - if Assigned(ThisClass) then - AppendShortDescrCell(TREl, ThisClass); + AppendHyperlink(CodeEl, ThisClass); + if Assigned(PrevClass) and (PrevClass Is TPasClassType) then // Interfaces from prevClass + AppendInterfaceInfo(CodeEl, TPasClassType(PrevClass)); + AppendShortDescrCell(TREl, ThisClass); if Assigned(ThisTreeNode) then if Assigned(ThisTreeNode.ParentNode) then @@ -1852,6 +1876,7 @@ begin TDEl := CreateTD(CreateTR(TableEl)); TDEl['align'] := 'center'; AppendText(TDEl, '|'); + PrevClass:= ThisClass; ThisClass := ThisTreeNode.ParentNode.Element; ThisTreeNode := ThisTreeNode.ParentNode; end @@ -1859,6 +1884,7 @@ begin begin ThisClass := nil; ThisTreeNode:= nil; + PrevClass:= nil; break; end else diff --git a/avx512-0037785/utils/fpdoc/dw_ipflin.pas b/avx512-0037785/utils/fpdoc/dw_ipflin.pas index 8bf9e117cc..b8bdf9c981 100644 --- a/avx512-0037785/utils/fpdoc/dw_ipflin.pas +++ b/avx512-0037785/utils/fpdoc/dw_ipflin.pas @@ -151,7 +151,7 @@ type implementation uses - SysUtils, dwriter; + fpdocstrs, SysUtils, dwriter; { TFPDocWriter overrides } diff --git a/avx512-0037785/utils/fpdoc/dw_latex.pp b/avx512-0037785/utils/fpdoc/dw_latex.pp index ce04c3a082..d353bf1011 100644 --- a/avx512-0037785/utils/fpdoc/dw_latex.pp +++ b/avx512-0037785/utils/fpdoc/dw_latex.pp @@ -30,7 +30,7 @@ Procedure CreateLaTeXDocForPackage(APackage: TPasPackage; AEngine: TFPDocEngine) implementation -uses SysUtils, Classes, dwLinear, dwriter; +uses fpdocstrs, SysUtils, Classes, dwLinear, dwriter; Type @@ -638,7 +638,7 @@ var begin Writer := TLaTeXWriter.Create(APackage, AEngine); try - Writer.WriteDoc; + Writer.DoWriteDocumentation; finally Writer.Free; end; diff --git a/avx512-0037785/utils/fpdoc/dw_linrtf.pp b/avx512-0037785/utils/fpdoc/dw_linrtf.pp index dd25f5a7f0..35a8667b27 100644 --- a/avx512-0037785/utils/fpdoc/dw_linrtf.pp +++ b/avx512-0037785/utils/fpdoc/dw_linrtf.pp @@ -28,7 +28,7 @@ Procedure CreateRTFDocForPackage(APackage: TPasPackage; AEngine: TFPDocEngine); implementation -uses SysUtils, Classes, dwLinear, dwriter; +uses fpdocstrs, SysUtils, Classes, dwLinear, dwriter; const Indent = 300; @@ -782,7 +782,7 @@ var begin Writer := TRTFWriter.Create(APackage, AEngine); try - Writer.WriteDoc; + Writer.DoWriteDocumentation; finally Writer.Free; end; diff --git a/avx512-0037785/utils/fpdoc/dw_man.pp b/avx512-0037785/utils/fpdoc/dw_man.pp index 1874bdf1ef..6811d5c858 100644 --- a/avx512-0037785/utils/fpdoc/dw_man.pp +++ b/avx512-0037785/utils/fpdoc/dw_man.pp @@ -99,9 +99,10 @@ Type Procedure WriteExampleFile(FN : String); virtual; procedure WriteExample(ADocNode: TDocNode); procedure WriteSeeAlso(ADocNode: TDocNode; Comma : Boolean); + // Here we write the documentation. + procedure DoWriteDocumentation; override; Public Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; - procedure WriteDoc; override; // Documentation writing methods. // Package Procedure WritePackagePage; @@ -185,6 +186,8 @@ Type implementation +uses fpdocstrs; + { TManWriter } constructor TManWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine); @@ -968,7 +971,7 @@ end; Actual man page writing ---------------------------------------------------------------------} -procedure TManWriter.WriteDoc; +procedure TManWriter.DoWriteDocumentation; var i : Integer; diff --git a/avx512-0037785/utils/fpdoc/dw_markdown.pp b/avx512-0037785/utils/fpdoc/dw_markdown.pp index e9a74d90b6..15358fa9e9 100644 --- a/avx512-0037785/utils/fpdoc/dw_markdown.pp +++ b/avx512-0037785/utils/fpdoc/dw_markdown.pp @@ -116,6 +116,8 @@ type procedure CreateClassMemberPageBody(AElement: TPasElement); virtual; procedure CreateInheritanceSubpage(aClass: TPasClassType; aTitle : string; AFilter: TMemberFilter); virtual; procedure CreateSortedSubpage(ACLass: TPasClassType; aTitle : string; AFilter: TMemberFilter ); virtual; + // Here we write the documentation + Procedure DoWriteDocumentation; override; public constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; destructor Destroy; override; @@ -126,7 +128,6 @@ type // Start producing html complete package documentation Function InterPretOption(Const Cmd,Arg : String) : boolean; override; - Procedure WriteDoc; override; Class Function FileNameExtension : String; override; class procedure Usage(List: TStrings); override; Class procedure SplitImport(var AFilename, ALinkPrefix: String); override; @@ -142,7 +143,7 @@ type implementation -uses SysUtils, fpdocclasstree; +uses fpdocstrs, SysUtils, fpdocclasstree; Function FixHTMLpath(S : String) : STring; @@ -300,9 +301,7 @@ begin end; end; - - -procedure TMarkdownWriter.WriteDoc; +procedure TMarkdownWriter.DoWriteDocumentation; begin Inherited; @@ -310,7 +309,6 @@ begin WriteMkdocsYaml; end; - function TMarkdownWriter.GetFooterMarkDown: TStrings; begin If FFooterMarkDown=Nil then @@ -423,7 +421,7 @@ begin break; ThisPackage := ThisPackage.NextSibling; end; - if Length(s) = 0 then + if (Length(s) = 0) and Assigned(Module) then begin { Okay, then we have to try all imported units of the current module } UnitList := Module.InterfaceSection.UsesList; @@ -650,6 +648,7 @@ procedure TMarkdownWriter.AppendSeeAlsoSection(AElement: TPasElement; DocNode: T else N:='?'; DoLog(SErrUnknownLinkID, [s,N,aID]); + LinkUnresolvedInc(); end ; if doBold then DescrBeginBold @@ -1474,12 +1473,19 @@ begin if aEL.ExternalName<>'' then aLine:=aLine+' external name '''+ael.ExternalName+''''; if Assigned(aEL.AncestorType) then + if (aEL.AncestorType is TPasSpecializeType) then begin - aLine:=aLine+' ('+ael.AncestorType.Name; - if Assigned(ael.Interfaces) and (aEl.Interfaces.Count>0) then - For I:=0 to aEl.Interfaces.Count-1 do - aLine:=aLine+', '+TPasElement(aEl.Interfaces[i]).Name; - aLine:=aLine+')'; + aLine:=aLine+'(specialize '; + aLine:=aLine+ TPasSpecializeType(aEL.AncestorType).DestType.Name; + aLine:=aLine+ '<,>)'; + end + else + begin + aLine:=aLine+' ('+ael.AncestorType.Name; + if Assigned(ael.Interfaces) and (aEl.Interfaces.Count>0) then + For I:=0 to aEl.Interfaces.Count-1 do + aLine:=aLine+', '+TPasElement(aEl.Interfaces[i]).Name; + aLine:=aLine+')'; end; if Assigned(aEl.GUIDExpr) then aLine:=aLine+' ['+aEl.GUIDExpr.GetDeclaration(True)+']'; @@ -1578,7 +1584,7 @@ procedure TMarkdownWriter.CreateClassMainPage(aClass : TPasClassType); var i: Integer; ThisInterface, - ThisClass: TPasClassType; + ThisClass: TPasType; ThisTreeNode: TPasElementNode; DocNode: TDocNode; @@ -1628,12 +1634,12 @@ begin // Show class item if Assigned(ThisClass) Then AppendHyperlink(ThisClass); - if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then + if Assigned(ThisClass) and (AClass.Interfaces.count>0) then begin AppendText('('); - for i:=0 to ThisClass.interfaces.count-1 do + for i:=0 to AClass.interfaces.count-1 do begin - ThisInterface:=TPasClassType(ThisClass.Interfaces[i]); + ThisInterface:= TPasType(AClass.Interfaces[i]); if I>0 then AppendText(', '); AppendHyperlink( ThisInterface); diff --git a/avx512-0037785/utils/fpdoc/dw_txt.pp b/avx512-0037785/utils/fpdoc/dw_txt.pp index 9557b196d2..3305f2eb88 100644 --- a/avx512-0037785/utils/fpdoc/dw_txt.pp +++ b/avx512-0037785/utils/fpdoc/dw_txt.pp @@ -28,7 +28,7 @@ Procedure CreateTxtDocForPackage(APackage: TPasPackage; AEngine: TFPDocEngine); implementation -uses SysUtils, Classes, dwLinear; +uses fpdocstrs, SysUtils, Classes, dwLinear; Const MaxListLevel = 10; @@ -603,7 +603,7 @@ var begin Writer := TTxtWriter.Create(APackage, AEngine); try - Writer.WriteDoc; + Writer.DoWriteDocumentation; finally Writer.Free; end; diff --git a/avx512-0037785/utils/fpdoc/dw_xml.pp b/avx512-0037785/utils/fpdoc/dw_xml.pp index 1f7bfbce51..b1ccbdcdc6 100644 --- a/avx512-0037785/utils/fpdoc/dw_xml.pp +++ b/avx512-0037785/utils/fpdoc/dw_xml.pp @@ -38,10 +38,11 @@ Type procedure AllocatePackagePages; override; procedure AllocateModulePages(AModule: TPasModule; {%H-}LinkList: TObjectList); override; procedure WriteDocPage(const aFileName: String; aElement: TPasElement; {%H-}aSubPageIndex: Integer); override; + // Here we write the documentation. + Procedure DoWriteDocumentation; override; public constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; function ModuleToXMLStruct(AModule: TPasModule): TXMLDocument; - Procedure WriteDoc; override; class procedure Usage(List: TStrings); override; function InterPretOption(const Cmd,Arg : String): boolean; override; end; @@ -61,6 +62,8 @@ Type implementation +uses fpdocstrs; + const DefaultVisibility = [visDefault, visPublic, visPublished, visProtected]; @@ -108,6 +111,8 @@ var visAutomated : Result := 'automated'; visStrictPrivate : Result := 'strictprivate'; visStrictProtected : Result := 'strictprotected'; + visRequired : Result := 'required'; + visOptional : Result := 'optional'; end; end; @@ -629,9 +634,9 @@ end; { TXMLWriter } -procedure TXMLWriter.WriteDoc; +procedure TXMLWriter.DoWriteDocumentation; begin - inherited WriteDoc; + inherited DoWriteDocumentation; end; function TXMLWriter.CreateAllocator: TFileAllocator; diff --git a/avx512-0037785/utils/fpdoc/dwlinear.pp b/avx512-0037785/utils/fpdoc/dwlinear.pp index 5b36cec805..c19c1f3a26 100644 --- a/avx512-0037785/utils/fpdoc/dwlinear.pp +++ b/avx512-0037785/utils/fpdoc/dwlinear.pp @@ -89,11 +89,12 @@ Type Property LastURL : DomString Read FLastURL Write FLastURL; // Overriden from fpdocwriter; procedure DescrWriteText(const AText: DOMString); override; + // Actual writing happens here. + Procedure DoWriteDocumentation; override; Public Constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; function InterpretOption(const Cmd, Arg: String): Boolean; override; class procedure Usage(List: TStrings); override; - procedure WriteDoc; override; // Linear Documentation writing methods. Procedure ProcessPackage; Procedure ProcessTopics(DocNode : TDocNode; Alevel : Integer); @@ -121,6 +122,8 @@ Type implementation +uses fpdocstrs; + const cDupLinkedDocParam = '--duplinkeddoc'; @@ -591,7 +594,7 @@ begin Result := '<nil>'; end; -procedure TLinearWriter.WriteDoc; +procedure TLinearWriter.DoWriteDocumentation; var i : Integer; diff --git a/avx512-0037785/utils/fpdoc/dwriter.pp b/avx512-0037785/utils/fpdoc/dwriter.pp index eb0bf599cf..e22d1d7ba4 100644 --- a/avx512-0037785/utils/fpdoc/dwriter.pp +++ b/avx512-0037785/utils/fpdoc/dwriter.pp @@ -27,31 +27,6 @@ interface uses Classes, DOM, contnrs, dGlobals, PasTree, SysUtils, fpdocclasstree; -resourcestring - SErrFileWriting = 'An error occurred during writing of file "%s": %s'; - - SErrInvalidShortDescr = 'Invalid short description'; - SErrInvalidDescr = 'Invalid description (illegal XML element: "%s")'; - SErrInvalidParaContent = 'Invalid paragraph content'; - SErrInvalidElementInList = 'Invalid element in list - only "li" allowed'; - SErrInvalidListContent = 'Invalid list content'; - SErrInvalidRemarkContent = 'Invalid <remark> content (illegal XML element: "%s")'; - SErrListIsEmpty = 'List is empty - need at least one "li" element'; - SErrInvalidDefinitionTermContent = 'Invalid content in definition term'; - SErrDefinitionEntryMissing = 'Definition entry after definition term is missing'; - SErrInvalidBorderValue = 'Invalid "border" value for %s'; - SErrInvalidTableContent = 'Invalid table content'; - SErrTableRowEmpty = 'Table row is empty (no "td" elements found)'; - SErrInvalidContentBeforeSectionTitle = 'Invalid content before section title'; - SErrSectionTitleExpected = 'Section title ("title" element) expected'; - - SErrDescrTagUnknown = 'Warning: Unknown tag "%s" in description'; - SErrUnknownEntityReference = 'Warning: Unknown entity reference "&%s;" found'; - SErrUnknownLinkID = 'Warning: Target ID of <link> in unit "%s", element "%s", is unknown: "%s"'; - SErrUnknownPrintShortID = 'Warning: Target ID of <printshort> is unknown: "%s"'; - SErrUnknownLink = 'Could not resolve link to "%s"'; - SErralreadyRegistered = 'Class for output format "%s" already registered'; - SErrUnknownWriterClass = 'Unknown output format "%s"'; type // Phony element for pas pages. @@ -116,6 +91,7 @@ type procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False); Procedure DoLog(Const Msg : String); Procedure DoLog(Const Fmt : String; Args : Array of const); + Procedure OutputResults(); virtual; procedure Warning(AContext: TPasElement; const AMsg: String); procedure Warning(AContext: TPasElement; const AMsg: String; const Args: array of const); @@ -194,6 +170,9 @@ type procedure DescrEndTableRow; virtual; abstract; procedure DescrBeginTableCell; virtual; abstract; procedure DescrEndTableCell; virtual; abstract; + procedure PrepareDocumentation; virtual; + // Descendents must override this. + procedure DoWriteDocumentation; virtual; Abstract; Property CurrentContext : TPasElement Read FContext ; public @@ -209,7 +188,8 @@ type Class Function FileNameExtension : String; virtual; Class Procedure Usage(List : TStrings); virtual; Class procedure SplitImport(var AFilename, ALinkPrefix: String); virtual; - procedure WriteDoc; virtual; Abstract; + // Here we start the generation of documentation + procedure WriteDocumentation; Function WriteDescr(Element: TPasElement) : TDocNode; procedure WriteDescr(Element: TPasElement; DocNode: TDocNode); procedure WriteDescr(AContext: TPasElement; DescrNode: TDOMElement); virtual; @@ -275,14 +255,23 @@ Type FCurDirectory: String; FModule: TPasModule; FPageInfos: TFPObjectList; // list of TPageInfo objects + FLinkUnresolvedCnt: Integer; + FOutputPageNames: TStringList; + function GetOutputPageNames: TStrings; function GetPageCount: Integer; - + function LinkFix(ALink:String):String; Protected FAllocator: TFileAllocator; - function ResolveLinkID(const Name: String; Level: Integer=0): DOMString; + Procedure LinkUnresolvedInc(); + // General resolving routine + function ResolveLinkID(const Name: String): DOMString; + // Simplified resolving routine. Excluded last path after dot + function ResolveLinkIDUnStrict(const Name: String): DOMString; function ResolveLinkIDInUnit(const Name,AUnitName: String): DOMString; function ResolveLinkWithinPackage(AElement: TPasElement; ASubpageIndex: Integer): String; - Function CreateAllocator : TFileAllocator; virtual; abstract; + procedure PrepareDocumentation; override; + function CreateAllocator() : TFileAllocator; virtual; abstract; + Procedure OutputResults(); override; // aFileName is the filename allocated by the Allocator, nothing prefixed. procedure WriteDocPage(const aFileName: String; aElement: TPasElement; aSubPageIndex: Integer); virtual; abstract; procedure AllocatePages; virtual; @@ -297,18 +286,22 @@ Type function GetFileBaseDir(aOutput: String): String; virtual; function InterPretOption(const Cmd, Arg: String): boolean; override; function ModuleHasClasses(AModule: TPasModule): Boolean; + // Allocate pages etc. + Procedure DoWriteDocumentation; override; + Function MustGeneratePage(aFileName : String) : Boolean; virtual; + Property PageInfos : TFPObjectList Read FPageInfos; Property SubPageNames: Boolean Read FSubPageNames; Public constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override; Destructor Destroy; override; - procedure WriteDoc; override; class procedure Usage(List: TStrings); override; property PageCount: Integer read GetPageCount; Property Allocator : TFileAllocator Read FAllocator; Property Module: TPasModule Read FModule Write FModule; Property CurDirectory: String Read FCurDirectory Write FCurDirectory; // relative to curdir of process property BaseDirectory: String read FBaseDirectory Write FBaseDirectory; // relative path to package base directory + Property OutputPageNames : TStrings Read GetOutputPageNames; end; TFPDocWriterClass = Class of TFPDocWriter; @@ -339,6 +332,8 @@ function SortPasElements(Item1, Item2: Pointer): Integer; implementation +uses strutils, fpdocstrs; + function SortPasElements(Item1, Item2: Pointer): Integer; begin Result:=CompareText(TPasElement(Item1).Name,TPasElement(Item2).Name) @@ -412,6 +407,7 @@ begin inherited Create(APackage, AEngine); FPageInfos:=TFPObjectList.Create; FSubPageNames:= False; + FLinkUnresolvedCnt:=0; end; destructor TMultiFileDocWriter.Destroy; @@ -426,23 +422,80 @@ begin Result := PageInfos.Count; end; -function TMultiFileDocWriter.ResolveLinkID(const Name: String; Level : Integer = 0): DOMString; +function TMultiFileDocWriter.GetOutputPageNames: TStrings; +begin + If (FoutputPageNames=Nil) then + begin + FOutputPageNames:=TStringList.Create; + FOutputPageNames.Sorted:=True; + end; + Result:=FOutputPageNames; +end; + +procedure TMultiFileDocWriter.OutputResults(); +begin + DoLog('Unresolved links: %d', [FLinkUnresolvedCnt]); + inherited OutputResults(); +end; + +procedure TMultiFileDocWriter.LinkUnresolvedInc(); +begin + Inc(FLinkUnresolvedCnt); +end; +function TMultiFileDocWriter.ResolveLinkID(const Name: String): DOMString; var - res,s: String; + res: String; begin res:=Engine.ResolveLink(Module,Name, True); // engine can return backslashes on Windows + res:= LinkFix(res); + Result:=UTF8Decode(res); +end; + +function TMultiFileDocWriter.ResolveLinkIDUnStrict(const Name: String + ): DOMString; +var + idDot, idLast: Integer; + res: String; +begin + res:=Engine.ResolveLink(Module,Name, True); + if res = '' then + begin + // do simplify on one level from end. + // TOCO: I want to move that code to last check of Engine.ResolveLink() for not Strict + IdDot:= Pos('.', Name); + IdLast:= 0; + // search last dot + while idDot > 0 do + begin + IdLast:= idDot; + IdDot:= Pos('.', Name, IdLast+1); + end; + if idLast > 0 then + // have cut last element + res:= Engine.ResolveLink(Module, Copy(Name, 1, IdLast-1), True); + end; + res:= LinkFix(res); + Result:=UTF8Decode(res); +end; + +function TMultiFileDocWriter.LinkFix(ALink: String): String; +var + res, s:String; +begin + res:= ALink; if Length(res) > 0 then - begin - s:=Copy(Res, 1, Length(CurDirectory) + 1); + begin + // If the link is in the same directory as current dir, then remove the directory part. + s:=Copy(res, 1, Length(CurDirectory) + 1); if (S= CurDirectory + '/') or (s= CurDirectory + '\') then - Res := Copy(Res, Length(CurDirectory) + 2, Length(Res)) - else if not IsLinkAbsolute(Res) then - Res := BaseDirectory + Res; - end; - Result:=UTF8Decode(Res); + res := Copy(res, Length(CurDirectory) + 2, Length(res)) + else if not IsLinkAbsolute(res) then + res := BaseDirectory + res; + end; + Result:= res; end; { Used for: @@ -482,8 +535,15 @@ begin SetLength(Result, 0); end; +procedure TMultiFileDocWriter.PrepareDocumentation; +begin + inherited PrepareDocumentation; + FAllocator:= CreateAllocator(); + FAllocator.SubPageNames:= SubPageNames; +end; -Function TMultiFileDocWriter.AddPage(AElement: TPasElement; ASubpageIndex: Integer) : TPageInfo; +function TMultiFileDocWriter.AddPage(AElement: TPasElement; + ASubpageIndex: Integer): TPageInfo; begin Result:= TPageInfo.Create(aElement,aSubPageIndex); @@ -531,7 +591,7 @@ begin end; -Function TMultiFileDocWriter.ModuleHasClasses(AModule: TPasModule) : Boolean; +function TMultiFileDocWriter.ModuleHasClasses(AModule: TPasModule): Boolean; begin result:=assigned(AModule) @@ -574,7 +634,8 @@ begin end; end; -Procedure TMultiFileDocWriter.AllocateClassMemberPages(AModule: TPasModule; LinkList : TObjectList); +procedure TMultiFileDocWriter.AllocateClassMemberPages(AModule: TPasModule; + LinkList: TObjectList); var i, j, k: Integer; ClassEl: TPasClassType; @@ -738,7 +799,7 @@ begin Result:=IncludeTrailingPathDelimiter(Result); end; -procedure TMultiFileDocWriter.WriteDoc; +procedure TMultiFileDocWriter.DoWriteDocumentation; procedure CreatePath(const AFilename: String); @@ -771,8 +832,6 @@ var FinalFilename: String; begin - FAllocator:=CreateAllocator; - FAllocator.SubPageNames:= SubPageNames; AllocatePages; DoLog(SWritingPages, [PageCount]); if Engine.Output <> '' then @@ -781,23 +840,60 @@ begin with TPageInfo(PageInfos[i]) do begin FileName:= Allocator.GetFilename(Element, SubpageIndex); - FinalFilename := GetFileBaseDir(Engine.Output) + FileName; - CreatePath(FinalFilename); - WriteDocPage(FileName,ELement,SubPageIndex); + if MustGeneratePage(FileName) then + begin + FinalFilename := GetFileBaseDir(Engine.Output) + FileName; + CreatePath(FinalFilename); + WriteDocPage(FileName,ELement,SubPageIndex); + end; end; end; +function TMultiFileDocWriter.MustGeneratePage(aFileName: String): Boolean; +begin + Result:=Not Assigned(FOutputPageNames); + if Not Result then + Result:=FOutputPageNames.IndexOf(aFileName)<>-1; + Writeln(afilename ,': ',result); +end; + class procedure TMultiFileDocWriter.Usage(List: TStrings); begin List.AddStrings(['--use-subpagenames', SUsageSubNames]); + List.AddStrings(['--only-pages=LIST', SUsageOnlyPages]); end; function TMultiFileDocWriter.InterPretOption(const Cmd, Arg: String): boolean; + +Var + I : Integer; + FN : String; + begin + Writeln('Cmd : ',Cmd); Result := True; if Cmd = '--use-subpagenames' then FSubPageNames:= True else + if Cmd = '--only-pages' then + begin + Result:=Arg<>''; + if Result then + begin + if Arg[1]='@' then + begin + FN:=Copy(Arg,2,Length(Arg)-1); + OutputPageNames.LoadFromFile(FN); + end + else + begin + For I:=1 to WordCount(Arg,[',']) do + OutputPageNames.Add(ExtractWord(I,Arg,[','])); + end; + Writeln('OutputPagenames ',OutputPagenames.CommaText); + end + end + else Result:=inherited InterPretOption(Cmd, Arg); end; @@ -971,7 +1067,7 @@ function TLongNameFileAllocator.GetFilename(AElement: TPasElement; ASubindex: In var n,s: String; i: Integer; - + MElement: TPasElement; begin Result:=''; if AElement.ClassType = TPasPackage then @@ -1009,7 +1105,9 @@ begin end else Result := LowerCase(AElement.PathName); // cut off Package Name - AElement:= AElement.GetModule; + MElement:= AElement.GetModule; + if Assigned(MElement) then + AElement:= MElement; Result := Copy(Result, Length(AElement.Parent.Name) + 2, MaxInt); // to skip dots in unit name i := Length(AElement.Name); @@ -1065,8 +1163,8 @@ begin FPackage := APackage; FTopics:=Tlist.Create; FImgExt:='.png'; - TreeClass:= TClassTreeBuilder.Create(FEngine, FPackage, okClass); - TreeInterface:= TClassTreeBuilder.Create(FEngine, FPackage, okInterface); + TreeClass:= TClassTreeBuilder.Create(FEngine, FPackage, okWithFields); + TreeInterface:= TClassTreeBuilder.Create(FEngine, FPackage, [okInterface]); CreateClassTree; end; @@ -1129,6 +1227,13 @@ begin end; end; +procedure TFPDocWriter.WriteDocumentation; +begin + PrepareDocumentation(); + DoWriteDocumentation(); + OutputResults(); +end; + function TFPDocWriter.FindTopicElement ( Node: TDocNode ) : TTopicElement; Var @@ -1152,6 +1257,11 @@ begin DoLog('%s : No support for images yet: %s (caption: "%s")',[ClassName,AFileName,ACaption]); end; +procedure TFPDocWriter.PrepareDocumentation; +begin + // Ancestors can call AllocatePages();CreateAllocator(); into base class +end; + { --------------------------------------------------------------------- Generic documentation node conversion ---------------------------------------------------------------------} @@ -1509,6 +1619,11 @@ begin DoLog(Format(Fmt,Args)); end; +procedure TFPDocWriter.OutputResults(); +begin + DoLog('Package: %s - Documentation process finished.', [FPackage.Name]); +end; + function TFPDocWriter.ConvertExtShort(AContext: TPasElement; Node: TDOMNode): Boolean; begin @@ -1722,8 +1837,8 @@ begin if Node.NodeType <> ELEMENT_NODE then begin if Node.NodeType = TEXT_NODE then - Result := IsWhitespaceNode(TDOMText(Node)) - else + Result := IsWhitespaceNode(TDOMText(Node)) + else Result := Node.NodeType = COMMENT_NODE; exit; end; diff --git a/avx512-0037785/utils/fpdoc/fpclasschart.pp b/avx512-0037785/utils/fpdoc/fpclasschart.pp index 1ce706f8bb..4172a5d81b 100644 --- a/avx512-0037785/utils/fpdoc/fpclasschart.pp +++ b/avx512-0037785/utils/fpdoc/fpclasschart.pp @@ -42,7 +42,7 @@ type FTree : TClassTreeBuilder; FObjects : TStringList; public - Constructor Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind); + Constructor Create(AClassTree : TXMLDocument; AObjectKindSet : TPasObjKindSet); Destructor Destroy; override; function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement; AVisibility :TPasMemberVisibility; @@ -442,14 +442,12 @@ begin end; end; -Constructor TClassTreeEngine.Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind); - - +Constructor TClassTreeEngine.Create(AClassTree : TXMLDocument; AObjectKindSet : TPasObjKindSet); begin + Inherited Create; FPackage:=TPasPackage.Create('dummy',Nil); - FTree:=TClassTreeBuilder.Create(Self,FPackage,AObjectKind); + FTree:=TClassTreeBuilder.Create(Self,FPackage,AObjectKindSet); FObjects:=TStringList.Create; - Inherited Create; end; destructor TClassTreeEngine.Destroy; @@ -538,11 +536,13 @@ Var end; begin + Result:= 0; aSrc:=TXMLDocument.Create(); try aSrc.AppendChild(aSrc.CreateElement('TObject')); AppendChildClasses(aSrc.DocumentElement,aRootNode); MergeTrees(Dest,aSrc); + Inc(Result); finally aSrc.Free; end; @@ -578,7 +578,7 @@ begin end; For I:=0 to InputFiles.Count-1 do begin - Engine := TClassTreeEngine.Create(XML,AObjectKind); + Engine := TClassTreeEngine.Create(XML,[AObjectKind]); Try ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget); Engine.Ftree.BuildTree(Engine.FObjects); diff --git a/avx512-0037785/utils/fpdoc/fpdoc.lpi b/avx512-0037785/utils/fpdoc/fpdoc.lpi index b9c99b0c3f..201f6383a8 100644 --- a/avx512-0037785/utils/fpdoc/fpdoc.lpi +++ b/avx512-0037785/utils/fpdoc/fpdoc.lpi @@ -8,6 +8,7 @@ <SaveOnlyProjectUnits Value="True"/> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> <SaveJumpHistory Value="False"/> <SaveFoldState Value="False"/> <CompatibilityMode Value="True"/> @@ -46,7 +47,7 @@ <PackageName Value="FCL"/> </Item1> </RequiredPackages> - <Units Count="20"> + <Units Count="21"> <Unit0> <Filename Value="fpdoc.pp"/> <IsPartOfProject Value="True"/> @@ -134,6 +135,10 @@ <Filename Value="dw_basehtml.pp"/> <IsPartOfProject Value="True"/> </Unit19> + <Unit20> + <Filename Value="fpdocstrs.pp"/> + <IsPartOfProject Value="True"/> + </Unit20> </Units> </ProjectOptions> <CompilerOptions> @@ -143,13 +148,22 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../../packages/fcl-passrc/src"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Linking> <Debugging> <DebugInfoType Value="dsDwarf3"/> + <UseHeaptrc Value="True"/> </Debugging> </Linking> + <Other> + <CustomOptions Value="-dCheckPasTreeRefCountx +-dDebugRefCountx"/> + <OtherDefines Count="1"> + <Define0 Value="CheckPasTreeRefCount"/> + </OtherDefines> + </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> diff --git a/avx512-0037785/utils/fpdoc/fpdoc.pp b/avx512-0037785/utils/fpdoc/fpdoc.pp index 5e789409e1..abbc8863d8 100644 --- a/avx512-0037785/utils/fpdoc/fpdoc.pp +++ b/avx512-0037785/utils/fpdoc/fpdoc.pp @@ -14,7 +14,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. } - +{$mode objfpc} +{$h+} program FPDoc; uses @@ -37,7 +38,7 @@ uses dw_man, // Man page writer dw_linrtf, // linear RTF writer dw_txt, // TXT writer - fpdocproj, mkfpdoc, dw_basemd, dw_basehtml; + fpdocproj, mkfpdoc, dw_basemd, dw_basehtml, fpdocstrs; Type @@ -101,9 +102,14 @@ begin Writeln(SUsageOption190); Writeln(SUsageOption200); Writeln(SUsageOption210); + Writeln(SUsageOption211); + Writeln(SUsageOption212); Writeln(SUsageOption215); Writeln(SUsageOption215A); Writeln(SUsageOption220); + Writeln(SUsageOption221); + Writeln(SUsageOption222); + Writeln(SUsageOption223); Writeln(SUsageOption230); Writeln(SUsageOption240); Writeln(SUsageOption250); @@ -151,7 +157,11 @@ end; procedure TFPDocApplication.ExceptProc(Sender: TObject; E: Exception); begin + OutputLog(Sender, Format('Exception: Class - %s', [E.ClassName])); + OutputLog(Sender, E.Message); +{$IFDEF EXCEPTION_STACK} OutputLog(Sender, DumpExceptionCallStack(E)); +{$ENDIF} end; destructor TFPDocApplication.Destroy; @@ -305,8 +315,16 @@ begin Usage(0) else if s = '--hide-protected' then FCreator.Options.HideProtected := True + else if s = '--fallback-seealso-links' Then + FCreator.Options.FallBackSeeAlsoLinks := True else if s = '--warn-no-node' then FCreator.Options.WarnNoNode := True + else if s = '--warn-documentation-empty' then + FCreator.Options.WarnDocumentationEmpty := True + else if s = '--info-used-file' then + FCreator.Options.InfoUsedFile := True + else if s = '--warn-XCT' then + FCreator.Options.WarnXCT := True else if s = '--show-private' then FCreator.Options.ShowPrivate := True else if s = '--stop-on-parser-error' then @@ -430,15 +448,15 @@ end; constructor TFPDocApplication.Create(AOwner: TComponent); begin inherited Create(AOwner); - StopOnException:=true; + StopOnException:=false; FCreator:=TFPDocCreator.Create(Self); FCreator.OnLog:=@OutputLog; OnException:= @ExceptProc; end; begin - //AssignFile(Output, 'fpdoc.log'); - //rewrite(Output); + //AssignFile(StdErr, 'fpdoc_err.log'); + //rewrite(StdErr); With TFPDocApplication.Create(Nil) do try Run; diff --git a/avx512-0037785/utils/fpdoc/fpdocclasstree.pp b/avx512-0037785/utils/fpdoc/fpdocclasstree.pp index 3ea8c84d65..2dc99839ba 100644 --- a/avx512-0037785/utils/fpdoc/fpdocclasstree.pp +++ b/avx512-0037785/utils/fpdoc/fpdocclasstree.pp @@ -2,6 +2,7 @@ unit fpdocclasstree; {$mode objfpc}{$H+} + interface uses @@ -9,21 +10,23 @@ uses Type + TPasObjKindSet = set of TPasObjKind; + { TPasElementNode } TPasElementNode = Class Private - FElement : TPasClassType; + FElement : TPasType; FParentNode: TPasElementNode; FChildren : TFPObjectList; function GetChild(aIndex : Integer): TPasElementNode; function GetChildCount: Integer; Public - Constructor Create (aElement : TPasClassType); + Constructor Create (aElement : TPasType); Destructor Destroy; override; Procedure AddChild(C : TPasElementNode); Procedure SortChildren; - Property Element : TPasClassType Read FElement; + Property Element : TPasType Read FElement; Property ParentNode : TPasElementNode read FParentNode; Property Children [aIndex : Integer] : TPasElementNode Read GetChild; Property ChildCount : Integer Read GetChildCount; @@ -35,17 +38,17 @@ Type Private FEngine:TFPDocEngine; FElementList : TFPObjectHashTable; - FObjectKind : TPasObjKind; + FObjectKind : TPasObjKindSet; FPackage: TPasPackage; FParentObject : TPasClassType; FRootNode : TPasElementNode; FRootObjectName : string; FRootObjectPathName : string; Protected - function AddToList(aElement: TPasClassType): TPasElementNode; + function AddToList(aElement: TPasType): TPasElementNode; Public Constructor Create(AEngine:TFPDocEngine; APackage : TPasPackage; - AObjectKind : TPasObjKind = okClass); + AObjectKind : TPasObjKindSet = okWithFields); Destructor Destroy; override; Function BuildTree(AObjects : TStringList) : Integer; Procedure SaveToXml(AFileName: String); @@ -56,6 +59,9 @@ Type implementation +uses + fpdocstrs, pasresolver; + { TPasElementNode } function SortOnElementName(Item1, Item2: Pointer): Integer; @@ -79,7 +85,7 @@ begin Result:=0 end; -constructor TPasElementNode.Create(aElement: TPasClassType); +constructor TPasElementNode.Create(aElement: TPasType); begin FElement:=aElement; end; @@ -104,33 +110,36 @@ begin end; constructor TClassTreeBuilder.Create(AEngine:TFPDocEngine; APackage : TPasPackage; - AObjectKind: TPasObjKind); + AObjectKind: TPasObjKindSet); begin FEngine:= AEngine; FPackage:= APAckage; FObjectKind:=AObjectKind; - Case FObjectkind of - okInterface : + if (okInterface in FObjectkind) then begin FRootObjectPathName:='#rtl.System.IInterface'; FRootObjectName:= 'IInterface'; - end; - okObject, okClass : + end + else if (FObjectkind * okWithFields) <> [] then begin FRootObjectPathName:='#rtl.System.TObject'; FRootObjectName:= 'TObject'; end - else + else // TODO: I don`t know need it ? Without that the code may be simplified. begin FRootObjectPathName:='#rtl.System.TObject'; FRootObjectName:= 'TObject'; end; - end; FParentObject:=TPasClassType.Create(FRootObjectName,FEngine.FindModule('System')); if not Assigned(FParentObject) then FParentObject:=TPasClassType.Create(FRootObjectName,FPackage); - FParentObject.ObjKind:=FObjectKind; + if (okInterface in FObjectkind) then + FParentObject.ObjKind:=okInterface + else if (FObjectkind * okWithFields) <> [] then + FParentObject.ObjKind:=okClass + else + FParentObject.ObjKind:=okClass; FRootNode:=TPasElementNode.Create(FParentObject); FRootNode.FParentNode := nil; FElementList:=TFPObjectHashTable.Create(False); @@ -145,29 +154,42 @@ begin Inherited; end; -function TClassTreeBuilder.AddToList ( aElement: TPasClassType +function TClassTreeBuilder.AddToList ( aElement: TPasType ) : TPasElementNode; Var aParentNode : TPasElementNode; aName : String; + aElementClass: TPasClassType; begin - Result:= nil; - if (aElement.ObjKind <> FObjectKind) then exit; + Result:= nil; aElementClass:=nil; + if (aElement is TPasClassType) then + aElementClass:= TPasClassType(aElement); + if Assigned(aElementClass) and not (aElementClass.ObjKind in FObjectKind) then exit; + if not Assigned(aElementClass) and not (aElement is TPasAliasType) then exit; + aParentNode:= nil; if aElement=Nil then aName:=FRootObjectName + else if (aElement is TPasAliasType) then + aName:=TPasAliasType(aElement).DestType.FullName else aName:=aElement.PathName; Result:=TPasElementNode(FElementList.Items[aName]); if (Result=Nil) then begin - if aElement.AncestorType is TPasClassType then - aParentNode:=AddToList(aElement.AncestorType as TPasClassType); + if Assigned(aElementClass) and ( + (aElementClass.AncestorType is TPasClassType) or + (aElementClass.AncestorType is TPasAliasType) + ) then + aParentNode:=AddToList(aElementClass.AncestorType); if not Assigned(aParentNode) then aParentNode:=FRootNode; - Result:=TPasElementNode.Create(aElement); + if (aElement is TPasAliasType) then + Result:=TPasElementNode.Create(TPasAliasType(TPasType(aElement)).DestType) + else + Result:=TPasElementNode.Create(aElement); aParentNode.AddChild(Result); Result.FParentNode := aParentNode; FElementList.Add(aName,Result); @@ -227,10 +249,11 @@ procedure TClassTreeBuilder.SaveToXml ( AFileName: String ); for CounterVar := 0 to ParentPasEl.ChildCount-1 do begin PasElNode:= ParentPasEl.Children[CounterVar]; - xmlEl:= AXmlDoc.CreateElement(UnicodeString(PasElNode.Element.Name)); + xmlEl:= AXmlDoc.CreateElement(UTF8Decode(PasElNode.Element.Name)); M:= PasElNode.Element.GetModule; - xmlEl['unit'] := UnicodeString(M.Name); - xmlEl['package'] := UnicodeString(M.PackageName); + xmlEl['unit'] := UTF8Decode(M.Name); + xmlEl['package'] := UTF8Decode(M.PackageName); + xmlEl['type'] := UTF8Decode(GetElementTypeName(PasElNode.Element)); ParentxmlEl.AppendChild(xmlEl); AddPasElChildsToXml(xmlEl, PasElNode); end; @@ -244,17 +267,24 @@ begin XmlDoc:= TXMLDocument.Create; XmlDoc.AppendChild(XmlDoc.CreateComment(UTF8Decode(SDocGeneratedByComment))); try - XmlRootEl:= XmlDoc.CreateElement(UnicodeString(FRootNode.Element.Name)); + XmlRootEl:= XmlDoc.CreateElement(UTF8Decode(FRootNode.Element.Name)); M:= FRootNode.Element.GetModule; if Assigned(M) then begin - XmlRootEl['unit'] := UnicodeString(M.Name); - XmlRootEl['package'] := UnicodeString(M.PackageName); + XmlRootEl['unit'] := UTF8Decode(M.Name); + XmlRootEl['package'] := UTF8Decode(M.PackageName); + XmlRootEl['type'] := UTF8Decode(GetElementTypeName(FRootNode.Element)); end else begin XmlRootEl['unit'] := 'system'; XmlRootEl['package'] := 'rtl'; + if (okWithFields * FObjectKind) <> [] then + XmlRootEl['type'] := 'class' + else if (okInterface in FObjectKind) then + XmlRootEl['type'] := 'interface' + else + XmlRootEl['type'] := 'class'; end; XmlDoc.AppendChild(XmlRootEl); AddPasElChildsToXml(XmlRootEl, FRootNode); diff --git a/avx512-0037785/utils/fpdoc/fpdocproj.pas b/avx512-0037785/utils/fpdoc/fpdocproj.pas index 7ea90f3401..7ab8020431 100644 --- a/avx512-0037785/utils/fpdoc/fpdocproj.pas +++ b/avx512-0037785/utils/fpdoc/fpdocproj.pas @@ -55,13 +55,17 @@ Type FFormat: String; FHidePrivate: Boolean; FHideProtected: Boolean; + FFallBackSeeAlsoLinks: Boolean; FIO: Boolean; FLanguage: String; FMoDir: String; FOSTarget: String; FSOPE: Boolean; + FWarnDocumentationEmpty: Boolean; FWarnNoNode: Boolean; FDontTrim : Boolean; + FInfoUsedFile: Boolean; + FWarnXCT: Boolean; procedure SetBackendOptions(const AValue: TStrings); Public Constructor Create; @@ -76,7 +80,11 @@ Type Property BackendOptions : TStrings Read FBackEndoptions Write SetBackendOptions; Property StopOnParseError : Boolean Read FSOPE Write FSOPE; Property HideProtected : Boolean Read FHideProtected Write FHideProtected; + Property FallBackSeeAlsoLinks :Boolean Read FFallBackSeeAlsoLinks Write FFallBackSeeAlsoLinks; Property WarnNoNode : Boolean Read FWarnNoNode Write FWarnNoNode; + Property InfoUsedFile : Boolean Read FInfoUsedFile Write FInfoUsedFile; + Property WarnDocumentationEmpty : Boolean Read FWarnDocumentationEmpty Write FWarnDocumentationEmpty; + Property WarnXCT : Boolean Read FWarnXCT Write FWarnXCT; Property ShowPrivate : Boolean Read FHidePrivate Write FHidePrivate; Property InterfaceOnly : Boolean Read FIO Write FIO; Property MoDir : String Read FMoDir Write FMODir; @@ -189,6 +197,9 @@ begin FSOPE:=O.StopOnParseError; HideProtected:=O.HideProtected; WarnNoNode:=O.WarnNoNode; + InfoUsedFile:=O.InfoUsedFile; + WarnDocumentationEmpty:=O.WarnDocumentationEmpty; + WarnXCT:=O.WarnXCT; ShowPrivate:=O.ShowPrivate; InterfaceOnly:=O.InterfaceOnly; MoDir:=O.MoDir; diff --git a/avx512-0037785/utils/fpdoc/fpdocstrs.pp b/avx512-0037785/utils/fpdoc/fpdocstrs.pp new file mode 100644 index 0000000000..2e58cf64f4 --- /dev/null +++ b/avx512-0037785/utils/fpdoc/fpdocstrs.pp @@ -0,0 +1,256 @@ +unit fpdocstrs; + +{$mode objfpc}{$H+} + +interface + +resourcestring + // Output strings + SDocPackageTitle = 'Reference for package ''%s'''; + SDocPackageMenuTitle = 'Package ''%s'''; + SDocPackageLinkTitle = 'Package'; + SDocPrograms = 'Programs'; + SDocUnits = 'Units'; + SDocUnitTitle = 'Reference for unit ''%s'''; + SDocUnitMenuTitle = 'Unit ''%s'''; + SDocInheritanceHierarchy = 'Inheritance Hierarchy'; + SDocInterfaceSection = 'Interface section'; + SDocImplementationSection = 'Implementation section'; + SDocUsedUnits = 'Used units'; + SDocUsedUnitsByUnitXY = 'Used units by unit ''%s'''; + SDocConstsTypesVars = 'Constants, types and variables'; + SDocResStrings = 'Resource strings'; + SDocTypes = 'Types'; + SDocType = 'Type'; + SDocConstants = 'Constants'; + SDocConstant = 'Constant'; + SDocClasses = 'Classes'; + SDocClass = 'Class'; + SDocProceduresAndFunctions = 'Procedures and functions'; + SDocProcedureOrFunction = 'Procedure/function'; + SDocVariables = 'Variables'; + SDocVariable = 'Variable'; + SDocIdentifierIndex = 'Index'; + SDocPackageClassHierarchy = 'Class hierarchy'; + SDocModuleIndex = 'Index of all identifiers in unit ''%s'''; + SDocPackageIndex = 'Index of all identifiers in package ''%s'''; + SDocUnitOverview = 'Overview of unit ''%s'''; + SDocOverview = 'Overview'; + SDocSearch = 'Search'; + SDocDeclaration = 'Declaration'; + SDocDescription = 'Description'; + SDocErrors = 'Errors'; + SDocVersion = 'Version info'; + SDocSeeAlso = 'See also'; + SDocExample = 'Example'; + SDocArguments = 'Arguments'; + SDocFunctionResult = 'Function result'; + SDocRemark = 'Remark: '; + SDocMethodOverview = 'Method overview'; + SDocPropertyOverview = 'Property overview'; + SDocEventOverview = 'Event overview'; + SDocInterfacesOverview = 'Interfaces overview'; + SDocInterface = 'Interfaces'; + SDocPage = 'Page'; + SDocMember = 'Member'; + SDocMembers = 'Members'; + SDocField = 'Field'; + SDocMethod = 'Method'; + SDocProperty = 'Property'; + SDocAccess = 'Access'; + SDocInheritance = 'Inheritance'; + SDocProperties = 'Properties'; + SDocMethods = 'Methods'; + SDocEvents = 'Events'; + SDocByName = 'by Name'; + SDocByInheritance = 'By inheritance'; + SDocValue = 'Value'; + SDocExplanation = 'Explanation'; + SDocProcedure = 'Procedure'; + SDocValuesForEnum = 'Enumeration values for type %s'; + SDocSourcePosition = 'Source position: %s line %d'; + SDocSynopsis = 'Synopsis'; + SDocVisibility = 'Visibility'; + SDocOpaque = 'Opaque type'; + SDocDateGenerated = 'Documentation generated on: %s'; + // The next line requires leading/trailing space due to XML comment layout: + SDocGeneratedByComment = ' Generated using FPDoc - (c) 2000-2021 FPC contributors and Sebastian Guenther, sg@freepascal.org '; + SDocNotes = 'Notes'; + SDocName = 'Name'; + SDocType_s = 'Type(s)'; + SDocTopic = 'Topic'; + SDocNoneAVailable = 'No members available'; + + // Topics + SDocRelatedTopics = 'Related topics'; + SDocUp = 'Up'; + SDocNext = 'Next'; + SDocPrevious = 'Previous'; + + // Various backend constants + SDocChapter = 'Chapter'; + SDocSection = 'Section'; + SDocSubSection = 'Subsection'; + SDocTable = 'Table'; + SDocListing = 'Listing'; + + // Man page usage + SManUsageManSection = 'Use ASection as the man page section'; + SManUsageNoUnitPrefix = 'Do not prefix man pages with unit name.'; + SManUsageWriterDescr = 'UNIX man page output.'; + SManUsagePackageDescription = 'Use descr as the description of man pages'; + + // HTML usage + SHTMLUsageFooter = 'Append xhtml (@filename reads from file) as footer to html page'; + SHTMLUsageNavigator = 'Append xhtml (@filename reads from file) in navigator bar'; + SHTMLUsageHeader = 'Append xhtml (@filename reads from file) as header to html page below navigation bar'; + SHTMLUsageFooterDate = 'Append footer with date. fmt is Optional format for FormatDateTime'; + SHTMLUsageCharset = 'Set the HTML character set'; + SHTMLHtmlSearch = 'Add search page with given name to the menu bar'; + SHTMLIndexColcount = 'Use N columns in the identifier index pages'; + SHTMLImageUrl = 'Prefix image URLs with url'; + SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css'; + + // CHM usage + SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.'; + SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.'; + SCHMUsageDefPage = 'Set the "Home" page relative to where it lives in the chm. i.e. "/index.html"'; + SCHMUsageOtrFiles= 'A txt file containing a list of files to be added relative to the working directory.'; + SCHMUsageCSSFile = 'Filename of a .css file to be included in the chm.'; + SCHMUsageAutoTOC = 'Automatically generate a Table of Contents. Ignores --toc-file'; + SCHMUsageAutoIDX = 'Automatically generate an Index. Ignores --index-file'; + SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*'; + SCHMUsageChmTitle= 'Title of the chm. Defaults to the value from --package'; + + // MarkDown usage + SMDUsageFooter = 'Append markdown (@filename reads from file) as footer to every markdown page'; + SMDUsageHeader = 'Prepend markdown (@filename reads from file) as header to every markdown page'; + SMDIndexColcount = 'Use N columns in the identifier index pages'; + SMDImageUrl = 'Prefix image URLs with url'; + SMDTheme = 'Use name as theme name'; + SMDNavigation = 'Use scheme for navigation tree, here scheme is one of:'; + SMDNavSubtree = ' UnitSubTree : put all units in a sub tree of a Units node'; + SMDNavTree = ' UnitTree : put every units as a node on the same level as packages node'; + + SXMLUsageFlatStructure = 'Use a flat output structure of XML files and directories'; + SXMLUsageSource = 'Include source file and line info in generated XML'; + + // Linear usage + SLinearUsageDupLinkedDocsP1 = 'Duplicate linked element documentation in'; + SLinearUsageDupLinkedDocsP2 = 'descendant classes.'; + + STitle = 'FPDoc - Free Pascal Documentation Tool'; + SVersion = 'Version %s [%s]'; + SCopyright1 = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org'; + SCopyright2 = '(c) 2005 - 2021 various FPC contributors'; + + SCmdLineHelp = 'Usage: %s [options]'; + SUsageOption008 = '--base-descr-dir=DIR prefix all description files with this directory'; + SUsageOption009 = '--base-input-dir=DIR prefix all input files with this directory'; + SUsageOption010 = '--content Create content file for package cross-references'; + SUsageOption020 = '--cputarget=value Set the target CPU for the scanner.'; + SUsageOption030 = '--descr=file use file as description file, e.g.: '; + SUsageOption035 = ' --descr=c:\WIP\myzipperdoc.xml'; + SUsageOption040 = ' This option is allowed more than once'; + SUsageOption050 = '--descr-dir=Dir Add All XML files in Dir to list of description files'; + SUsageOption060 = '--format=fmt Select output format.'; + SUsageOption070 = '--help Show this help.'; + SUsageOption080 = '--hide-protected Do not show protected methods in overview'; + SUsageOption090 = '--import=file Import content file for package cross-references'; + SUsageOption100 = '--input=cmd use cmd as input for the parser, e.g.:'; + SUsageOption110 = ' --input=C:\fpc\packages\paszlib\src\zipper.pp'; + SUsageOption120 = ' At least one input option is required.'; + SUsageOption130 = '--input-dir=Dir Add All *.pp and *.pas files in Dir to list of input files'; + SUsageOption140 = '--lang=lng Select output language.'; + SUsageOption145 = '--macro=name=value Define a macro to preprocess the project file with.'; + SUsageOption150 = '--ostarget=value Set the target OS for the scanner.'; + SUsageOption160 = '--output=name use name as the output name.'; + SUsageOption170 = ' Each backend interprets this as needed.'; + SUsageOption180 = '--package=name Set the package name for which to create output,'; + SUsageOption190 = ' e.g. --package=fcl'; + SUsageOption200 = '--project=file Use file as project file'; + SUsageOption210 = '--show-private Show private methods.'; + SUsageOption211 = '--fallback-seealso-links'; + SUsageOption212 = ' Simplify seealso links by exluding last link level'; + SUsageOption215 = '--stop-on-parser-error'; + SUsageOption215A = ' Stop when a parser error occurs. Default is to ignore parser errors.'; + SUsageOption220 = '--warn-no-node Warn if no documentation node was found.'; + SUsageOption221 = '--warn-documentation-empty Warn if documentation is empty.'; + SUsageOption222 = '--warn-xct Warn if an external class could not be resolved.'; + SUsageOption223 = '--info-used-file Output the file path of an implicitly processed file.'; + SUsageOption230 = '--mo-dir=dir Set directory where language files reside to dir'; + SUsageOption240 = '--parse-impl (Experimental) try to parse implementation too'; + SUsageOption250 = '--dont-trim Do not trim XML contents. Useful for preserving'; + SUsageOption260 = ' formatting inside e.g <pre> tags'; + SUsageOption270 = '--write-project=file'; + SUsageOption280 = ' Do not write documentation, create project file instead'; + SUsageOption290 = '--verbose Write more information on the screen'; + SUsageOption300 = '--dry-run Only parse sources and XML, do not create output'; + SUsageOption310 = '--write-project=file'; + SUsageOption320 = ' Write all command-line options to a project file'; + SUsageSubNames = 'Use the file subnames instead the indexes as postfixes'; + SUsageOnlyPages = 'Only write pages in LIST, LIST is comma-separated list of filenames or @filename where the named file contains 1 file per line.'; + + SUsageFormats = 'The following output formats are supported by this fpdoc:'; + SUsageBackendHelp = 'Specify an output format, combined with --help to get more help for this backend.'; + SUsageFormatSpecific = 'Output format "%s" supports the following options:'; + SCmdLineErrInvalidMacro = 'Macro needs to be in the form name=value'; + + SCmdLineInvalidOption = 'Ignoring unknown option "%s"'; + SCmdLineInvalidFormat = 'Invalid format "%s" specified'; + SCmdLineOutputOptionMissing = 'Need an output filename, please specify one with --output=<filename>'; + SWritingPages = 'Writing %d pages...'; + SNeedPackageName = 'No package name specified. Please specify one using the --package option.'; + SAvailablePackages = 'Available packages: '; + SDone = 'Done.'; + SErrCouldNotCreateOutputDir = 'Could not create output directory "%s"'; + SErrCouldNotCreateFile = 'Could not create file "%s": %s'; + SSeeURL = '(See %s)'; // For linear text writers. + SParsingUsedUnit = 'Parsing used unit "%s" with commandLine "%s"'; + + SErrFileWriting = 'An error occurred during writing of file "%s": %s'; + + SErrInvalidShortDescr = 'Invalid short description'; + SErrInvalidDescr = 'Invalid description (illegal XML element: "%s")'; + SErrInvalidParaContent = 'Invalid paragraph content'; + SErrInvalidElementInList = 'Invalid element in list - only "li" allowed'; + SErrInvalidListContent = 'Invalid list content'; + SErrInvalidRemarkContent = 'Invalid <remark> content (illegal XML element: "%s")'; + SErrListIsEmpty = 'List is empty - need at least one "li" element'; + SErrInvalidDefinitionTermContent = 'Invalid content in definition term'; + SErrDefinitionEntryMissing = 'Definition entry after definition term is missing'; + SErrInvalidBorderValue = 'Invalid "border" value for %s'; + SErrInvalidTableContent = 'Invalid table content'; + SErrTableRowEmpty = 'Table row is empty (no "td" elements found)'; + SErrInvalidContentBeforeSectionTitle = 'Invalid content before section title'; + SErrSectionTitleExpected = 'Section title ("title" element) expected'; + + SErrDescrTagUnknown = 'Warning: Unknown tag "%s" in description'; + SErrUnknownEntityReference = 'Warning: Unknown entity reference "&%s;" found'; + SErrUnknownLinkID = 'Warning: Target ID of <link> in unit "%s", element "%s", is unknown: "%s"'; + SErrUnknownPrintShortID = 'Warning: Target ID of <printshort> is unknown: "%s"'; + SErrUnknownLink = 'Could not resolve link to "%s"'; + SErralreadyRegistered = 'Class for output format "%s" already registered'; + SErrUnknownWriterClass = 'Unknown output format "%s"'; + + SErrCannotChangeIndentSizeWhenIndented = 'Cannot change indent size while text is indented.'; + SErrIndentMismatch = 'Indent mismatch: trying to undent when current indent too small'; + SErrNotInList = 'Not in list'; + SErrPopListStack = 'Pop list stack list type mismatch'; + SErrMinListStack = 'Min list stack reached'; + SErrMaxListStack = 'Max list stack reached'; + SErrMinIndentStack = 'Min indent stack reached'; + SErrMaxIndentStack = 'Max indent stack reached'; + + // doc xml + SErrInvalidRootNode = 'Invalid options root node: Got "%s", expected "docproject"'; + SErrNoPackagesNode = 'No "packages" node found in docproject'; + SErrNoInputFile = 'unit tag without file attribute found'; + SErrNoDescrFile = 'description tag without file attribute'; + SErrNoImportFile = 'Import tag without file attribute'; + SErrNoImportPrefix = 'Import tag without prefix attribute'; + +implementation + +end. + diff --git a/avx512-0037785/utils/fpdoc/fpdocxmlopts.pas b/avx512-0037785/utils/fpdoc/fpdocxmlopts.pas index b3897af126..c2fe4d25fe 100644 --- a/avx512-0037785/utils/fpdoc/fpdocxmlopts.pas +++ b/avx512-0037785/utils/fpdoc/fpdocxmlopts.pas @@ -44,15 +44,8 @@ Const implementation -Uses XMLRead, XMLWrite; - -Resourcestring - SErrInvalidRootNode = 'Invalid options root node: Got "%s", expected "docproject"'; - SErrNoPackagesNode = 'No "packages" node found in docproject'; - SErrNoInputFile = 'unit tag without file attribute found'; - SErrNoDescrFile = 'description tag without file attribute'; - SErrNoImportFile = 'Import tag without file attribute'; - SErrNoImportPrefix = 'Import tag without prefix attribute'; +Uses fpdocstrs, XMLRead, XMLWrite; + { TXMLFPDocOptions } diff --git a/avx512-0037785/utils/fpdoc/fpmake.pp b/avx512-0037785/utils/fpdoc/fpmake.pp index 1dabb89934..0ae4354525 100644 --- a/avx512-0037785/utils/fpdoc/fpmake.pp +++ b/avx512-0037785/utils/fpdoc/fpmake.pp @@ -42,6 +42,7 @@ begin P.Options.Add('-S2h'); T:=P.Targets.AddProgram('fpdoc.pp'); + T.Dependencies.AddUnit('fpdocstrs'); T.Dependencies.AddUnit('dglobals'); T.Dependencies.AddUnit('dw_ipflin'); T.Dependencies.AddUnit('dwriter'); @@ -65,17 +66,18 @@ begin T:=P.Targets.AddProgram('fpclasschart.pp'); T.ResourceStrings:=true; - T := P.Targets.AddUnit('dglobals.pp'); + T := P.Targets.AddUnit('fpdocstrs.pp'); T.install:=false; T.ResourceStrings:=true; + T := P.Targets.AddUnit('dglobals.pp'); + T.install:=false; + T := P.Targets.AddUnit('dwriter.pp'); T.install:=false; - T.ResourceStrings:=true; T := P.Targets.AddUnit('fpdocxmlopts.pas'); T.install:=false; - T.ResourceStrings:=true; P.Targets.AddUnit('dw_xml.pp').install:=false; P.Targets.AddUnit('sh_pas.pp').install:=false; @@ -84,7 +86,7 @@ begin P.Targets.AddUnit('dw_markdown.pp').install:=false; T:=P.Targets.AddUnit('dw_latex.pp'); T.install:=false; - T.ResourceStrings:=true; + P.Targets.AddUnit('dw_txt.pp').install:=false; P.Targets.AddUnit('dw_man.pp').install:=false; P.Targets.AddUnit('dwlinear.pp').install:=false; diff --git a/avx512-0037785/utils/fpdoc/makeskel.pp b/avx512-0037785/utils/fpdoc/makeskel.pp index 23c3daf2d4..3d0b637f29 100644 --- a/avx512-0037785/utils/fpdoc/makeskel.pp +++ b/avx512-0037785/utils/fpdoc/makeskel.pp @@ -23,7 +23,7 @@ program MakeSkel; {$h+} uses - SysUtils, Classes, Gettext, dGlobals, PasTree, PParser,PScanner; + fpdocstrs, SysUtils, Classes, Gettext, dGlobals, PasTree, PParser,PScanner; resourcestring STitle = 'MakeSkel - FPDoc skeleton XML description file generator'; diff --git a/avx512-0037785/utils/fpdoc/mkfpdoc.pp b/avx512-0037785/utils/fpdoc/mkfpdoc.pp index 019369425b..8b1b3cfa52 100644 --- a/avx512-0037785/utils/fpdoc/mkfpdoc.pp +++ b/avx512-0037785/utils/fpdoc/mkfpdoc.pp @@ -34,6 +34,7 @@ Type FProjectMacros: TStrings; FScannerLogEvents: TPScannerLogEvents; FVerbose: Boolean; + function GetLogLevels: TFPDocLogLevels; function GetOptions: TEngineOptions; function GetPackages: TFPDocPackages; procedure SetBaseDescrDir(AValue: String); @@ -73,6 +74,7 @@ Type implementation +uses fpdocstrs; { TFPDocCreator } @@ -84,6 +86,9 @@ begin begin ScannerLogEvents:=[sleFile]; ParserLogEvents:=[]; + Options.InfoUsedFile:= true; + Options.WarnDocumentationEmpty:= true; + Options.WarnXCT:= true; end else begin @@ -243,8 +248,8 @@ begin If not InterPretOption(Cmd,Arg) then DoLog(SCmdLineInvalidOption,[Cmd+'='+Arg]); end; - // Output created Documentation - WriteDoc; + // Create documentation by writer + WriteDocumentation(); Finally Free; end; @@ -255,6 +260,23 @@ begin Engine.WriteContentFile(APackage.ContentFile); end; +Function TFPDocCreator.GetLogLevels : TFPDocLogLevels; + + Procedure DoOpt(doSet : Boolean; aLevel: TFPDocLogLevel); + + begin + if DoSet then + Result:=Result+[aLevel]; + end; + +begin + Result:=[]; + DoOpt(Options.WarnNoNode,dleWarnNoNode); + DoOpt(Options.InfoUsedFile,dleWarnUsedFile); + DoOpt(Options.WarnDocumentationEmpty,dleDocumentationEmpty); + DoOpt(Options.WarnXCT,dleXCT); +end; + procedure TFPDocCreator.CreateDocumentation(APackage: TFPDocPackage; ParseOnly: Boolean); @@ -263,7 +285,7 @@ var Engine : TFPDocEngine; Cmd,Arg : String; WriterClass: TFPDocWriterClass; - + eMsg: String; begin Cmd:=''; FCurPackage:=APackage; @@ -291,35 +313,53 @@ begin Engine.HideProtected:=Options.HideProtected; Engine.HidePrivate:=Not Options.ShowPrivate; Engine.OnParseUnit:=@HandleOnParseUnit; - Engine.WarnNoNode:=Options.WarnNoNode; + Engine.DocLogLevels:=GetLogLevels; + Engine.FalbackSeeAlsoLinks:= Options.FallBackSeeAlsoLinks; if Length(Options.Language) > 0 then TranslateDocStrings(Options.Language); // scan the input source files for i := 0 to APackage.Inputs.Count - 1 do try - // get options from input packages - SplitInputFileOption(APackage.Inputs[i],Cmd,Arg); - arg:=Arg+' -d'+Options.EndianNess; - // make absolute filepath - Cmd:=FixInputFile(Cmd); - if FProcessedUnits.IndexOf(Cmd)=-1 then + try + eMsg:=''; + // get options from input packages + SplitInputFileOption(APackage.Inputs[i],Cmd,Arg); + arg:=Arg+' -d'+Options.EndianNess; + // make absolute filepath + Cmd:=FixInputFile(Cmd); + if FProcessedUnits.IndexOf(Cmd)=-1 then begin - FProcessedUnits.Add(Cmd); - - // Parce sources for OS Target - //WriteLn(Format('Parsing unit: %s', [ExtractFilenameOnly(Cmd)])); - ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]); + FProcessedUnits.Add(Cmd); + // Parce sources for OS Target + //WriteLn(Format('Parsing unit: %s', [ExtractFilenameOnly(Cmd)])); + ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]); // poSkipDefaultDefs end; - except - on E: EParserError do - If Options.StopOnParseError then - Raise - else + //else WriteLn(Format('Processed unit: %s', [ExtractFilenameOnly(Cmd)])); + except + on E: EParserError do begin - DoLog('Error: %s(%d,%d): %s',[E.Filename, E.Row, E.Column, E.Message]); - DoLog('Ignoring error, continuing with next unit (if any).'); + eMsg:= Format('Parser error: %s (%d,%d): %s',[E.Filename, E.Row, E.Column, E.Message]); + If Options.StopOnParseError then Raise; end; - end; + on E: EFileNotFoundError do + begin + eMsg:= Format('Error: file not found - %s', [E.Message]); + If Options.StopOnParseError then Raise; + end; + on E: Exception do + begin + eMsg:= Format('Error: %s', [E.Message]); + If Options.StopOnParseError then Raise; + end; + end; // try except + finally + if eMsg <> '' then + begin + DoLog(eMsg); + If not Options.StopOnParseError then + DoLog('Ignoring error, continuing with next unit (if any).'); + end; + end; // try finally if Not ParseOnly then begin Engine.StartDocumenting; diff --git a/avx512-0037785/utils/pas2js/dist/rtl.js b/avx512-0037785/utils/pas2js/dist/rtl.js index 3333f8268e..1300ffd5bb 100644 --- a/avx512-0037785/utils/pas2js/dist/rtl.js +++ b/avx512-0037785/utils/pas2js/dist/rtl.js @@ -707,10 +707,9 @@ var rtl = { }, intfAsIntfT: function (intf,intftype){ - if (intf){ - var i = rtl.getIntfG(intf.$o,intftype.$guid); - if (i!==null) return i; - } + if (!intf) return null; + var i = rtl.getIntfG(intf.$o,intftype.$guid); + if (i) return i; rtl.raiseEInvalidCast(); }, @@ -739,15 +738,20 @@ var rtl = { delete this[id]; old._Release(); // may fail } - this[id]=intf; + if(intf) { + this[id]=intf; + } return intf; }, free: function(){ //console.log('rtl.intfRefs.free...'); for (var id in this){ if (this.hasOwnProperty(id)){ - //console.log('rtl.intfRefs.free: id='+id+' '+this[id].$name+' $o='+this[id].$o.$classname); - this[id]._Release(); + var intf = this[id]; + if (intf){ + //console.log('rtl.intfRefs.free: id='+id+' '+intf.$name+' $o='+intf.$o.$classname); + intf._Release(); + } } } } |