Ver código fonte

* synchronised with trunk till r42189

git-svn-id: branches/debug_eh@42190 -
Jonas Maebe 6 anos atrás
pai
commit
faf75095cd
75 arquivos alterados com 3953 adições e 795 exclusões
  1. 10 0
      .gitattributes
  2. 2 0
      compiler/arm/armins.dat
  3. 1 1
      compiler/arm/armnop.inc
  4. 14 0
      compiler/arm/armtab.inc
  5. 7 5
      compiler/arm/narmmat.pas
  6. 73 28
      compiler/avr/aoptcpu.pas
  7. 3 2
      compiler/avr/cgcpu.pas
  8. 9 1
      compiler/cfileutl.pas
  9. 104 1
      compiler/hlcgobj.pas
  10. 12 2
      compiler/link.pas
  11. 0 29
      compiler/llvm/hlcgllvm.pas
  12. 34 0
      compiler/nadd.pas
  13. 47 0
      compiler/ogomf.pas
  14. 1 1
      compiler/symdef.pas
  15. 12 8
      compiler/systems/t_bsd.pas
  16. 2 1
      compiler/x86/rax86int.pas
  17. 1 0
      packages/chm/fpmake.pp
  18. 2 3
      packages/chm/src/chmcmd.lpr
  19. 237 84
      packages/chm/src/chmfilewriter.pas
  20. 185 97
      packages/chm/src/chmreader.pas
  21. 406 149
      packages/chm/src/chmsitemap.pas
  22. 34 0
      packages/chm/src/chmtypes.pas
  23. 105 36
      packages/chm/src/chmwriter.pas
  24. 2 0
      packages/fcl-base/examples/README.txt
  25. 27 0
      packages/fcl-base/examples/demoio.pp
  26. 32 0
      packages/fcl-base/examples/testappexit.pp
  27. 28 1
      packages/fcl-image/src/fpwritetiff.pas
  28. 4 6
      packages/fcl-image/src/freetype.pp
  29. 1 1
      packages/fcl-image/src/libfreetype.inc
  30. 222 221
      packages/fcl-passrc/src/pasresolver.pp
  31. 2 0
      packages/fcl-passrc/src/pparser.pp
  32. 22 0
      packages/fcl-passrc/tests/tcresolver.pas
  33. 1 1
      packages/pastojs/src/fppas2js.pp
  34. 39 0
      packages/pastojs/tests/tcmodules.pas
  35. 3 2
      packages/paszlib/src/zipper.pp
  36. 504 2
      packages/rtl-objpas/src/i386/invoke.inc
  37. 16 4
      packages/rtl-objpas/src/inc/rtti.pp
  38. 1 1
      packages/rtl-objpas/src/x86_64/invoke.inc
  39. 1 0
      packages/rtl-objpas/tests/testrunner.rtlobjpas.pp
  40. 18 3
      packages/rtl-objpas/tests/tests.rtti.impl.pas
  41. 1 1
      packages/winunits-base/src/imm.pas
  42. 963 4
      packages/winunits-base/src/shlwapi.pp
  43. 41 31
      rtl/avr/avr.inc
  44. 254 0
      rtl/avr/math.inc
  45. 10 0
      rtl/avr/setjump.inc
  46. 3 0
      rtl/avr/setjumph.inc
  47. 7 0
      rtl/beos/ossysc.inc
  48. 6 0
      rtl/bsd/ossysc.inc
  49. 12 2
      rtl/embedded/system.pp
  50. 1 0
      rtl/freebsd/sysnr.inc
  51. 10 1
      rtl/inc/getopts.pp
  52. 4 0
      rtl/inc/system.inc
  53. 63 3
      rtl/linux/arm/sighnd.inc
  54. 6 0
      rtl/linux/ossysc.inc
  55. 1 0
      rtl/msdos/dos.pp
  56. 23 18
      rtl/objpas/classes/classesh.inc
  57. 26 1
      rtl/objpas/classes/stringl.inc
  58. 1 0
      rtl/objpas/rtlconst.inc
  59. 12 12
      rtl/objpas/sysutils/syshelp.inc
  60. 5 2
      rtl/openbsd/i386/si_c.inc
  61. 5 2
      rtl/openbsd/i386/si_g.inc
  62. 1 0
      rtl/unix/bunxh.inc
  63. 1 0
      rtl/unix/oscdeclh.inc
  64. BIN
      tests/test/cg/obj/haiku/x86_64/cpptcl1.o
  65. BIN
      tests/test/cg/obj/haiku/x86_64/cpptcl2.o
  66. BIN
      tests/test/cg/obj/haiku/x86_64/ctest.o
  67. BIN
      tests/test/cg/obj/haiku/x86_64/tcext3.o
  68. BIN
      tests/test/cg/obj/haiku/x86_64/tcext4.o
  69. BIN
      tests/test/cg/obj/haiku/x86_64/tcext5.o
  70. BIN
      tests/test/cg/obj/haiku/x86_64/tcext6.o
  71. 1 0
      tests/test/cg/obj/readme.txt
  72. 223 0
      tests/test/cpu16/i8086/tfarcal2.pp
  73. 19 0
      tests/webtbs/tw35272.pp
  74. 30 27
      utils/fpdoc/dw_htmlchm.inc
  75. 0 1
      utils/fpdoc/fpdocxmlopts.pas

+ 10 - 0
.gitattributes

@@ -1947,6 +1947,7 @@ packages/fcl-base/examples/databom.txt svneol=native#text/plain
 packages/fcl-base/examples/dbugsrv.pp svneol=native#text/plain
 packages/fcl-base/examples/dbugsrv.pp svneol=native#text/plain
 packages/fcl-base/examples/debugtest.pp svneol=native#text/plain
 packages/fcl-base/examples/debugtest.pp svneol=native#text/plain
 packages/fcl-base/examples/decodeascii85.pp svneol=native#text/plain
 packages/fcl-base/examples/decodeascii85.pp svneol=native#text/plain
+packages/fcl-base/examples/demoio.pp svneol=native#text/plain
 packages/fcl-base/examples/dobserver.pp svneol=native#text/plain
 packages/fcl-base/examples/dobserver.pp svneol=native#text/plain
 packages/fcl-base/examples/doecho.pp svneol=native#text/plain
 packages/fcl-base/examples/doecho.pp svneol=native#text/plain
 packages/fcl-base/examples/dparser.pp svneol=native#text/plain
 packages/fcl-base/examples/dparser.pp svneol=native#text/plain
@@ -1996,6 +1997,7 @@ packages/fcl-base/examples/stringl.pp svneol=native#text/plain
 packages/fcl-base/examples/tarmakercons.pas svneol=native#text/plain
 packages/fcl-base/examples/tarmakercons.pas svneol=native#text/plain
 packages/fcl-base/examples/tarmakerconsgzip.pas svneol=native#text/plain
 packages/fcl-base/examples/tarmakerconsgzip.pas svneol=native#text/plain
 packages/fcl-base/examples/testapp.pp svneol=native#text/plain
 packages/fcl-base/examples/testapp.pp svneol=native#text/plain
+packages/fcl-base/examples/testappexit.pp svneol=native#text/plain
 packages/fcl-base/examples/testbf.pp svneol=native#text/plain
 packages/fcl-base/examples/testbf.pp svneol=native#text/plain
 packages/fcl-base/examples/testbs.pp svneol=native#text/plain
 packages/fcl-base/examples/testbs.pp svneol=native#text/plain
 packages/fcl-base/examples/testcgi.html -text
 packages/fcl-base/examples/testcgi.html -text
@@ -12037,6 +12039,13 @@ tests/test/cg/obj/haiku/i386/tcext3.o -text
 tests/test/cg/obj/haiku/i386/tcext4.o -text
 tests/test/cg/obj/haiku/i386/tcext4.o -text
 tests/test/cg/obj/haiku/i386/tcext5.o -text
 tests/test/cg/obj/haiku/i386/tcext5.o -text
 tests/test/cg/obj/haiku/i386/tcext6.o -text
 tests/test/cg/obj/haiku/i386/tcext6.o -text
+tests/test/cg/obj/haiku/x86_64/cpptcl1.o -text
+tests/test/cg/obj/haiku/x86_64/cpptcl2.o -text
+tests/test/cg/obj/haiku/x86_64/ctest.o -text
+tests/test/cg/obj/haiku/x86_64/tcext3.o -text
+tests/test/cg/obj/haiku/x86_64/tcext4.o -text
+tests/test/cg/obj/haiku/x86_64/tcext5.o -text
+tests/test/cg/obj/haiku/x86_64/tcext6.o -text
 tests/test/cg/obj/linux/aarch64/cpptcl1.o -text
 tests/test/cg/obj/linux/aarch64/cpptcl1.o -text
 tests/test/cg/obj/linux/aarch64/cpptcl2.o -text
 tests/test/cg/obj/linux/aarch64/cpptcl2.o -text
 tests/test/cg/obj/linux/aarch64/ctest.o -text
 tests/test/cg/obj/linux/aarch64/ctest.o -text
@@ -16628,6 +16637,7 @@ tests/webtbs/tw35187.pp svneol=native#text/pascal
 tests/webtbs/tw35224.pp svneol=native#text/plain
 tests/webtbs/tw35224.pp svneol=native#text/plain
 tests/webtbs/tw3523.pp svneol=native#text/plain
 tests/webtbs/tw3523.pp svneol=native#text/plain
 tests/webtbs/tw35233.pp svneol=native#text/plain
 tests/webtbs/tw35233.pp svneol=native#text/plain
+tests/webtbs/tw35272.pp svneol=native#text/plain
 tests/webtbs/tw3529.pp svneol=native#text/plain
 tests/webtbs/tw3529.pp svneol=native#text/plain
 tests/webtbs/tw3531.pp svneol=native#text/plain
 tests/webtbs/tw3531.pp svneol=native#text/plain
 tests/webtbs/tw3533.pp svneol=native#text/plain
 tests/webtbs/tw3533.pp svneol=native#text/plain

+ 2 - 0
compiler/arm/armins.dat

@@ -321,6 +321,7 @@ reg32,memam2              \x17\x04\x50                   ARM32,ARMv4
 reglo,memam3              \x65\x58\x0\2                  THUMB,ARMv4T
 reglo,memam3              \x65\x58\x0\2                  THUMB,ARMv4T
 reglo,memam4              \x66\x68\x0\2                  THUMB,ARMv4T
 reglo,memam4              \x66\x68\x0\2                  THUMB,ARMv4T
 reglo,memam5              \x67\x98\x0\2                  THUMB,ARMv4T
 reglo,memam5              \x67\x98\x0\2                  THUMB,ARMv4T
+reglo,memam2              \x67\x98\x0\2                  THUMB,ARMv4T
 reglo,memam6              \x67\x48\x0\2                  THUMB,ARMv4T
 reglo,memam6              \x67\x48\x0\2                  THUMB,ARMv4T
 reg32,memam2              \x88\xF8\x50\x0\x0\0           THUMB32,WIDE,ARMv6T2
 reg32,memam2              \x88\xF8\x50\x0\x0\0           THUMB32,WIDE,ARMv6T2
 reg32,memam2              \x17\x04\x10                   ARM32,ARMv4
 reg32,memam2              \x17\x04\x10                   ARM32,ARMv4
@@ -543,6 +544,7 @@ reg32,reglist		          \x26\x80			   ARM32,ARMv4
 reglo,memam3                \x65\x50\x0\2                  THUMB,ARMv4T
 reglo,memam3                \x65\x50\x0\2                  THUMB,ARMv4T
 reglo,memam4                \x66\x60\x0\2                  THUMB,ARMv4T
 reglo,memam4                \x66\x60\x0\2                  THUMB,ARMv4T
 reglo,memam5                \x67\x90\x0\2                  THUMB,ARMv4T
 reglo,memam5                \x67\x90\x0\2                  THUMB,ARMv4T
+reglo,memam2                \x67\x90\x0\2                  THUMB,ARMv4T
 reg32,memam2                \x88\xF8\x40\x0\x0\0           THUMB32,WIDE,ARMv6T2
 reg32,memam2                \x88\xF8\x40\x0\x0\0           THUMB32,WIDE,ARMv6T2
 reg32,memam2                \x17\x04\x00                   ARM32,ARMv4
 reg32,memam2                \x17\x04\x00                   ARM32,ARMv4
 
 

+ 1 - 1
compiler/arm/armnop.inc

@@ -1,2 +1,2 @@
 { don't edit, this file is generated from armins.dat }
 { don't edit, this file is generated from armins.dat }
-959;
+961;

+ 14 - 0
compiler/arm/armtab.inc

@@ -1043,6 +1043,13 @@
     code    : #103#152#0#2;
     code    : #103#152#0#2;
     flags   : if_thumb or if_armv4t
     flags   : if_thumb or if_armv4t
   ),
   ),
+  (
+    opcode  : A_LDR;
+    ops     : 2;
+    optypes : (ot_reglo,ot_memoryam2,ot_none,ot_none,ot_none,ot_none);
+    code    : #103#152#0#2;
+    flags   : if_thumb or if_armv4t
+  ),
   (
   (
     opcode  : A_LDR;
     opcode  : A_LDR;
     ops     : 2;
     ops     : 2;
@@ -2016,6 +2023,13 @@
     code    : #103#144#0#2;
     code    : #103#144#0#2;
     flags   : if_thumb or if_armv4t
     flags   : if_thumb or if_armv4t
   ),
   ),
+  (
+    opcode  : A_STR;
+    ops     : 2;
+    optypes : (ot_reglo,ot_memoryam2,ot_none,ot_none,ot_none,ot_none);
+    code    : #103#144#0#2;
+    flags   : if_thumb or if_armv4t
+  ),
   (
   (
     opcode  : A_STR;
     opcode  : A_STR;
     ops     : 2;
     ops     : 2;

+ 7 - 5
compiler/arm/narmmat.pas

@@ -164,7 +164,7 @@ implementation
                       cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,31,numerator,helper1);
                       cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,31,numerator,helper1);
                     if GenerateThumbCode then
                     if GenerateThumbCode then
                       begin
                       begin
-                        cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,32-power,helper1);
+                        cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,32-power,helper1);
                         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD,helper2,numerator,helper1));
                         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD,helper2,numerator,helper1));
                       end
                       end
                     else
                     else
@@ -179,9 +179,12 @@ implementation
                else
                else
                  cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
                  cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
              end
              end
-           else {Everything else is handled the generic code}
+           else if CPUARM_HAS_UMULL in cpu_capabilities[current_settings.cputype] then
+             {Everything else is handled the generic code}
              cg.g_div_const_reg_reg(current_asmdata.CurrAsmList,def_cgsize(resultdef),
              cg.g_div_const_reg_reg(current_asmdata.CurrAsmList,def_cgsize(resultdef),
-               tordconstnode(right).value.svalue,numerator,resultreg);
+               tordconstnode(right).value.svalue,numerator,resultreg)
+           else
+             internalerror(2019012601);
          end;
          end;
 
 
 {
 {
@@ -286,8 +289,7 @@ implementation
                 resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
                 resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
               end;
               end;
 
 
-            if (right.nodetype=ordconstn) and
-               (CPUARM_HAS_UMULL in cpu_capabilities[current_settings.cputype]) then
+            if (right.nodetype=ordconstn) then
               begin
               begin
                 if nodetype=divn then
                 if nodetype=divn then
                   genOrdConstNodeDiv
                   genOrdConstNodeDiv

+ 73 - 28
compiler/avr/aoptcpu.pas

@@ -42,6 +42,8 @@ Type
     function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
     function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
     function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
     function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
 
 
+    function InvertSkipInstruction(var p: tai): boolean;
+
     { uses the same constructor as TAopObj }
     { uses the same constructor as TAopObj }
     function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
     function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
     procedure PeepHoleOptPass2;override;
     procedure PeepHoleOptPass2;override;
@@ -225,6 +227,71 @@ Implementation
         end;
         end;
     end;
     end;
 
 
+
+  {
+    Turns
+      sbis ?
+      jmp .Lx
+      op
+    .Lx:
+
+    Into
+      sbic ?
+      op
+
+    For all types of skip instructions
+  }
+  function TCpuAsmOptimizer.InvertSkipInstruction(var p: tai): boolean;
+
+    function GetNextInstructionWithoutLabel(p: tai; var next: tai): boolean;
+      begin
+        repeat
+          result:=GetNextInstruction(p,next);
+          p:=next;
+        until
+          (not result) or
+          (not assigned(next)) or
+          (next.typ in [ait_instruction]);
+
+        result:=assigned(next) and (next.typ in [ait_instruction]);
+      end;
+
+    var
+      hp1, hp2, hp3: tai;
+      s: string;
+    begin
+      result:=false;
+
+      if GetNextInstruction(taicpu(p),hp1) and
+        (hp1.typ=ait_instruction) and
+        (taicpu(hp1).opcode in [A_RJMP,A_JMP]) and
+        (taicpu(hp1).ops=1) and
+        (taicpu(hp1).oper[0]^.typ=top_ref) and
+        (taicpu(hp1).oper[0]^.ref^.offset=0) and
+        (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
+        GetNextInstructionWithoutLabel(hp1,hp2) and
+        (hp2.typ=ait_instruction) and
+        (not taicpu(hp2).is_jmp) and
+        GetNextInstruction(hp2,hp3) and
+        FindLabel(TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol),hp3) then
+        begin
+          DebugMsg('SkipJump2InvertedSkip', p);
+
+          case taicpu(p).opcode of
+            A_SBIS: taicpu(p).opcode:=A_SBIC;
+            A_SBIC: taicpu(p).opcode:=A_SBIS;
+            A_SBRS: taicpu(p).opcode:=A_SBRC;
+            A_SBRC: taicpu(p).opcode:=A_SBRS;
+          end;
+
+          TAsmLabel(taicpu(hp1).oper[0]^.ref^.symbol).decrefs;
+
+          asml.remove(hp1);
+          hp1.free;
+        end;
+    end;
+
+
   function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
   function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
     var
     var
       hp1,hp2,hp3,hp4,hp5: tai;
       hp1,hp2,hp3,hp4,hp5: tai;
@@ -520,6 +587,9 @@ Implementation
 
 
                         result:=true;
                         result:=true;
                       end;
                       end;
+
+                    if InvertSkipInstruction(p) then
+                      result:=true;
                   end;
                   end;
                 A_ANDI:
                 A_ANDI:
                   begin
                   begin
@@ -810,7 +880,7 @@ Implementation
                        (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
                        (MatchInstruction(hp1,[A_PUSH,A_MOV,A_CP,A_CPC,A_ADD,A_SUB,A_ADC,A_SBC,A_EOR,A_AND,A_OR,
                                                A_OUT,A_IN]) or
                                                A_OUT,A_IN]) or
                        { the reference register of ST/STD cannot be replaced }
                        { the reference register of ST/STD cannot be replaced }
-                       (MatchInstruction(hp1,[A_STD,A_ST]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
+                       (MatchInstruction(hp1,[A_STD,A_ST,A_STS]) and (MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^)))) and
                        (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
                        (not RegModifiedByInstruction(taicpu(p).oper[0]^.reg, hp1)) and
                        {(taicpu(hp1).ops=1) and
                        {(taicpu(hp1).ops=1) and
                        (taicpu(hp1).oper[0]^.typ = top_reg) and
                        (taicpu(hp1).oper[0]^.typ = top_reg) and
@@ -1023,33 +1093,8 @@ Implementation
                           op
                           op
                         .L1:
                         .L1:
                     }
                     }
-                    if GetNextInstruction(p, hp1) and
-                       (hp1.typ=ait_instruction) and
-                       (taicpu(hp1).opcode in [A_JMP,A_RJMP]) and
-                       (taicpu(hp1).ops>0) and
-                       (taicpu(hp1).oper[0]^.typ = top_ref) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol is TAsmLabel) and
-                       GetNextInstruction(hp1, hp2) and
-                       (hp2.typ=ait_instruction) and
-                       (not taicpu(hp2).is_jmp) and
-                       GetNextInstruction(hp2, hp3) and
-                       (hp3.typ=ait_label) and
-                       (taicpu(hp1).oper[0]^.ref^.symbol=tai_label(hp3).labsym) then
-                      begin
-                        DebugMsg('Peephole SbiJmp2Sbi performed',p);
-
-                        if taicpu(p).opcode=A_SBIC then
-                          taicpu(p).opcode:=A_SBIS
-                        else
-                          taicpu(p).opcode:=A_SBIC;
-
-                        tai_label(hp3).labsym.decrefs;
-
-                        AsmL.remove(hp1);
-                        taicpu(hp1).Free;
-
-                        result:=true;
-                      end
+                    if InvertSkipInstruction(p) then
+                      result:=true
                     {
                     {
                       Turn
                       Turn
                           sbiX X, y
                           sbiX X, y

+ 3 - 2
compiler/avr/cgcpu.pas

@@ -274,8 +274,9 @@ unit cgcpu;
                   begin
                   begin
                     load_para_loc(r,hp);
                     load_para_loc(r,hp);
 
 
-                    for i2:=1 to tcgsize2size[hp^.Size] do
-                      r:=GetNextReg(r);
+                    if i<tcgsize2size[cgpara.Size] then
+                      for i2:=1 to tcgsize2size[hp^.Size] do
+                        r:=GetNextReg(r);
 
 
                     hp:=hp^.Next;
                     hp:=hp^.Next;
                   end;
                   end;

+ 9 - 1
compiler/cfileutl.pas

@@ -1284,8 +1284,16 @@ end;
 
 
 
 
    function  FindExe(const bin:TCmdStr;allowcache:boolean;var foundfile:TCmdStr):boolean;
    function  FindExe(const bin:TCmdStr;allowcache:boolean;var foundfile:TCmdStr):boolean;
+     var
+       b : TCmdStr;
      begin
      begin
-       FindExe:=FindFileInExeLocations(ChangeFileExt(bin,source_info.exeext),allowcache,foundfile);
+       { change extension only on platforms that use an exe extension, otherwise on OpenBSD
+         'ld.bfd' gets converted to 'ld' }
+       if source_info.exeext<>'' then
+         b:=ChangeFileExt(bin,source_info.exeext)
+       else
+         b:=bin;
+       FindExe:=FindFileInExeLocations(b,allowcache,foundfile);
      end;
      end;
 
 
 
 

+ 104 - 1
compiler/hlcgobj.pas

@@ -1416,12 +1416,57 @@ implementation
   procedure thlcgobj.a_load_subsetref_reg(list: TAsmList; fromsubsetsize, tosize: tdef; const sref: tsubsetreference; destreg: tregister);
   procedure thlcgobj.a_load_subsetref_reg(list: TAsmList; fromsubsetsize, tosize: tdef; const sref: tsubsetreference; destreg: tregister);
     var
     var
       tmpref: treference;
       tmpref: treference;
-      valuereg,extra_value_reg: tregister;
+      valuereg,extra_value_reg, tmpreg: tregister;
       tosreg: tsubsetregister;
       tosreg: tsubsetregister;
       loadsize: torddef;
       loadsize: torddef;
       loadbitsize: byte;
       loadbitsize: byte;
       extra_load: boolean;
       extra_load: boolean;
+      tmpsref: tsubsetreference;
     begin
     begin
+      if sref.bitlen>AIntBits then
+        begin
+          tmpsref:=sref;
+          tmpsref.bitlen:=AIntBits;
+          valuereg:=hlcg.getintregister(list,tosize);
+          a_load_subsetref_reg(list,sinttype,tosize,tmpsref,valuereg);
+          tmpsref.bitlen:=sref.bitlen-AIntBits;
+          inc(tmpsref.ref.offset,AIntBits div 8);
+          extra_value_reg:=hlcg.getintregister(list,tosize);
+          a_load_subsetref_reg(list,sinttype,tosize,tmpsref,extra_value_reg);
+          { can't use a_load_reg_subsetreg to merge the results, as that one
+            does not support sizes > AIntBits either }
+          tmpreg:=hlcg.getintregister(list,tosize);
+          if target_info.endian=endian_big then
+            begin
+              a_op_const_reg_reg(list,OP_SHL,tosize,sref.bitlen-AIntBits,valuereg,tmpreg);
+              if is_signed(fromsubsetsize) then
+                begin
+                  valuereg:=tmpreg;
+                  tmpreg:=hlcg.getintregister(list,tosize);
+                  a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl (sref.bitlen-AIntBits))-1,extra_value_reg,tmpreg);
+                  valuereg:=tmpreg;
+                end
+            end
+          else
+            begin
+              a_op_const_reg_reg(list,OP_SHL,tosize,AIntBits,extra_value_reg,tmpreg);
+              if is_signed(fromsubsetsize) then
+                begin
+                  extra_value_reg:=hlcg.getintregister(list,tosize);
+                  a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl AIntBits)-1,valuereg,extra_value_reg);
+                  valuereg:=extra_value_reg;
+                end
+            end;
+          if is_signed(fromsubsetsize) then
+            begin
+              extra_value_reg:=hlcg.getintregister(list,tosize);
+              a_op_const_reg_reg(list,OP_AND,tosize,(tcgint(1) shl AIntBits)-1,valuereg,extra_value_reg);
+              valuereg:=extra_value_reg;
+            end;
+          a_op_reg_reg_reg(list,OP_OR,tosize,valuereg,tmpreg,destreg);
+          exit;
+        end;
+
       get_subsetref_load_info(sref,loadsize,extra_load);
       get_subsetref_load_info(sref,loadsize,extra_load);
       loadbitsize:=loadsize.size*8;
       loadbitsize:=loadsize.size*8;
 
 
@@ -1512,7 +1557,37 @@ implementation
     end;
     end;
 
 
   procedure thlcgobj.a_load_reg_subsetref(list: TAsmList; fromsize, tosubsetsize: tdef; fromreg: tregister; const sref: tsubsetreference);
   procedure thlcgobj.a_load_reg_subsetref(list: TAsmList; fromsize, tosubsetsize: tdef; fromreg: tregister; const sref: tsubsetreference);
+    var
+      tmpsref: tsubsetreference;
+      fromreg1: tregister;
     begin
     begin
+      if sref.bitlen>AIntBits then
+        begin
+          if ((sref.bitlen mod AIntBits)<>0) then
+            internalerror(2019052901);
+          tmpsref:=sref;
+          tmpsref.bitlen:=AIntBits;
+          fromreg1:=hlcg.getintregister(list,uinttype);
+          a_load_reg_reg(list,fromsize,uinttype,fromreg,fromreg1);
+          if target_info.endian=endian_big then
+            begin
+              inc(tmpsref.ref.offset,sref.bitlen-AIntBits);
+            end;
+          a_load_reg_subsetref(list,uinttype,uinttype,fromreg1,tmpsref);
+          if target_info.endian=endian_big then
+            begin
+              tmpsref.ref.offset:=sref.ref.offset;
+            end
+          else
+            begin
+              inc(tmpsref.ref.offset,AIntBits div 8);
+            end;
+          tmpsref.bitlen:=sref.bitlen-AIntBits;
+          fromreg1:=hlcg.getintregister(list,fromsize);
+          hlcg.a_op_const_reg_reg(list,OP_SHR,fromsize,AIntBits,fromreg,fromreg1);
+          a_load_reg_subsetref(list,fromsize,tosubsetsize,fromreg1,tmpsref);
+          exit;
+        end;
       a_load_regconst_subsetref_intern(list,fromsize,tosubsetsize,fromreg,sref,SL_REG);
       a_load_regconst_subsetref_intern(list,fromsize,tosubsetsize,fromreg,sref,SL_REG);
     end;
     end;
 
 
@@ -1545,9 +1620,37 @@ implementation
 
 
   procedure thlcgobj.a_load_const_subsetref(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sref: tsubsetreference);
   procedure thlcgobj.a_load_const_subsetref(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sref: tsubsetreference);
     var
     var
+      tmpref: treference;
+      tmpsref: tsubsetreference;
       tmpreg: tregister;
       tmpreg: tregister;
       slopt: tsubsetloadopt;
       slopt: tsubsetloadopt;
+      newdef: tdef;
+      newbytesize: longint;
+      loval, hival: longint;
     begin
     begin
+      if sref.bitlen>AIntBits then
+        begin
+          if ((sref.bitlen mod AIntBits)<>0) then
+            internalerror(2019052901);
+          tmpsref:=sref;
+          tmpsref.bitlen:=AIntBits;
+          if target_info.endian=endian_big then
+            begin
+              inc(tmpsref.ref.offset,sref.bitlen-AIntBits);
+            end;
+          a_load_const_subsetref(list,tosubsetsize,aint(a),tmpsref);
+          if target_info.endian=endian_big then
+            begin
+              tmpsref.ref.offset:=sref.ref.offset;
+            end
+          else
+            begin
+              inc(tmpsref.ref.offset,AIntBits div 8);
+            end;
+          tmpsref.bitlen:=sref.bitlen-AIntBits;
+          a_load_const_subsetref(list,tosubsetsize,a shr AIntBits,tmpsref);
+          exit;
+        end;
       { perform masking of the source value in advance }
       { perform masking of the source value in advance }
       slopt:=SL_REGNOSRCMASK;
       slopt:=SL_REGNOSRCMASK;
       if (sref.bitlen<>AIntBits) then
       if (sref.bitlen<>AIntBits) then

+ 12 - 2
compiler/link.pas

@@ -691,10 +691,20 @@ Implementation
         if cs_link_on_target in current_settings.globalswitches then
         if cs_link_on_target in current_settings.globalswitches then
           begin
           begin
             { If linking on target, don't add any path PM }
             { If linking on target, don't add any path PM }
-            FindUtil:=ChangeFileExt(s,target_info.exeext);
+            { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets
+              converted to 'ld' }
+            if target_info.exeext<>'' then
+              FindUtil:=ChangeFileExt(s,target_info.exeext)
+            else
+              FindUtil:=s;
             exit;
             exit;
           end;
           end;
-        UtilExe:=ChangeFileExt(s,source_info.exeext);
+        { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets converted
+          to 'ld' }
+        if source_info.exeext<>'' then
+          UtilExe:=ChangeFileExt(s,source_info.exeext)
+        else
+          UtilExe:=s;
         FoundBin:='';
         FoundBin:='';
         Found:=false;
         Found:=false;
         if utilsdirectory<>'' then
         if utilsdirectory<>'' then

+ 0 - 29
compiler/llvm/hlcgllvm.pas

@@ -1102,35 +1102,6 @@ implementation
       invert: boolean;
       invert: boolean;
       fallthroughlab, falselab, tmplab: tasmlabel;
       fallthroughlab, falselab, tmplab: tasmlabel;
     begin
     begin
-      { since all comparisons return their results in a register, we'll often
-        get comparisons against true/false -> optimise }
-      if (size=pasbool1type) and
-         (cmp_op in [OC_EQ,OC_NE]) then
-        begin
-          { convert to an llvmbool1type and use directly }
-          tmpreg:=getintregister(list,llvmbool1type);
-          a_load_reg_reg(list,size,llvmbool1type,reg,tmpreg);
-          case cmp_op of
-            OC_EQ:
-              invert:=a=0;
-            OC_NE:
-              invert:=a=1;
-            else
-              { avoid uninitialised warning }
-              internalerror(2015031504);
-            end;
-          current_asmdata.getjumplabel(falselab);
-          fallthroughlab:=falselab;
-          if invert then
-            begin
-              tmplab:=l;
-              l:=falselab;
-              falselab:=tmplab;
-            end;
-          list.concat(taillvm.op_size_reg_lab_lab(la_br,llvmbool1type,tmpreg,l,falselab));
-          a_label(list,fallthroughlab);
-          exit;
-        end;
       tmpreg:=getregisterfordef(list,size);
       tmpreg:=getregisterfordef(list,size);
       a_load_const_reg(list,size,a,tmpreg);
       a_load_const_reg(list,size,a,tmpreg);
       a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
       a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);

+ 34 - 0
compiler/nadd.pas

@@ -1650,6 +1650,40 @@ implementation
                   andn,
                   andn,
                   orn:
                   orn:
                     begin
                     begin
+                      { in case of xor, or 'and' with full  and cbool: convert both to Pascal bool and then
+                        perform the xor/and to prevent issues with "longbool(1) and/xor
+                        longbool(2)" }
+                      if (is_cbool(ld) or is_cbool(rd)) and
+                         ((nodetype=xorn) or
+                          ((nodetype=andn) and
+                           ((cs_full_boolean_eval in current_settings.localswitches) or
+                            not(nf_short_bool in flags)
+                           )
+                          )
+                         ) then
+                        begin
+                          resultdef:=nil;
+                          if is_cbool(ld) then
+                            begin
+                              inserttypeconv(left,pasbool8type);
+                              ttypeconvnode(left).convtype:=tc_bool_2_bool;
+                              if not is_cbool(rd) or
+                                 (ld.size>=rd.size) then
+                                resultdef:=ld;
+                            end;
+                          if is_cbool(rd) then
+                            begin
+                              inserttypeconv(right,pasbool8type);
+                              ttypeconvnode(right).convtype:=tc_bool_2_bool;
+                              if not assigned(resultdef) then
+                                resultdef:=rd;
+                            end;
+                          result:=ctypeconvnode.create_explicit(caddnode.create(nodetype,left,right),resultdef);
+                          ttypeconvnode(result).convtype:=tc_bool_2_bool;
+                          left:=nil;
+                          right:=nil;
+                          exit;
+                        end;
                       { Make sides equal to the largest boolean }
                       { Make sides equal to the largest boolean }
                       if (torddef(left.resultdef).size>torddef(right.resultdef).size) or
                       if (torddef(left.resultdef).size>torddef(right.resultdef).size) or
                         (is_cbool(left.resultdef) and not is_cbool(right.resultdef)) then
                         (is_cbool(left.resultdef) and not is_cbool(right.resultdef)) then

+ 47 - 0
compiler/ogomf.pas

@@ -316,6 +316,53 @@ interface
         property MZFlatContentSection: TMZExeSection read GetMZFlatContentSection;
         property MZFlatContentSection: TMZExeSection read GetMZFlatContentSection;
       end;
       end;
 
 
+      TNewExeHeaderFlag = (
+        nehfSingleData,                                               { bit  0 }
+        nehfMultipleData,                                             { bit  1 }
+        { 'Global initialization' according to BP7's TDUMP.EXE                 }
+        nehfRealMode,                                                 { bit  2 }
+        nehfProtectedModeOnly,                                        { bit  3 }
+        { 'EMSDIRECT' according to OpenWatcom's wdump                          }
+        { '8086 instructions' according to Ralf Brown's Interrupt List         }
+        nehfReserved4,                                                { bit  4 }
+        { 'EMSBANK' according to OpenWatcom's wdump                            }
+        { '80286 instructions' according to Ralf Brown's Interrupt List        }
+        nehfReserved5,                                                { bit  5 }
+        { 'EMSGLOBAL' according to OpenWatcom's wdump                          }
+        { '80386 instructions' according to Ralf Brown's Interrupt List        }
+        nehfReserved6,                                                { bit  6 }
+        nehfNeedsFPU,                                                 { bit  7 }
+        { Not compatible with windowing API                                    }
+        nehfNotWindowAPICompatible,                                   { bit  8 }
+        { Compatible with windowing API                                        }
+        { (NotWindowAPICompatible + WindowAPICompatible) = Uses windowing API  }
+        nehfWindowAPICompatible,                                      { bit  9 }
+        { Family Application (OS/2) according to Ralf Brown's Interrupt List   }
+        nehfReserved10,                                               { bit 10 }
+        nehfSelfLoading,                                              { bit 11 }
+        nehfReserved12,                                               { bit 12 }
+        nehfLinkErrors,                                               { bit 13 }
+        nehfReserved14,                                               { bit 14 }
+        nehfIsDLL);                                                   { bit 15 }
+      TNewExeHeaderFlags = set of TNewExeHeaderFlag;
+
+      TNewExeAdditionalHeaderFlag = (
+        neahfLFNSupport,                                              { bit  0 }
+        neahfWindows2ProtectedMode,                                   { bit  1 }
+        neahfWindows2ProportionalFonts,                               { bit  2 }
+        neahfHasGangloadArea);                                        { bit  3 }
+      TNewExeAdditionalHeaderFlags = set of TNewExeAdditionalHeaderFlag;
+
+      TNewExeTargetOS = (
+        netoUnknown                        = $00,
+        netoOS2                            = $01,
+        netoWindows                        = $02,
+        netoMultitaskingMsDos4             = $03,
+        netoWindows386                     = $04,
+        netoBorlandOperatingSystemServices = $05,
+        netoPharLap286DosExtenderOS2       = $81,
+        netoPharLap286DosExtenderWindows   = $82);
+
       TOmfAssembler = class(tinternalassembler)
       TOmfAssembler = class(tinternalassembler)
         constructor create(info: pasminfo; smart:boolean);override;
         constructor create(info: pasminfo; smart:boolean);override;
       end;
       end;

+ 1 - 1
compiler/symdef.pas

@@ -3074,7 +3074,7 @@ implementation
                   system_x86_64_linux,system_x86_64_freebsd,
                   system_x86_64_linux,system_x86_64_freebsd,
                   system_x86_64_openbsd,system_x86_64_netbsd,
                   system_x86_64_openbsd,system_x86_64_netbsd,
                   system_x86_64_solaris,system_x86_64_embedded,
                   system_x86_64_solaris,system_x86_64_embedded,
-                  system_x86_64_dragonfly] then
+                  system_x86_64_dragonfly,system_x86_64_haiku] then
                savesize:=16
                savesize:=16
              else
              else
                savesize:=12;
                savesize:=12;

+ 12 - 8
compiler/systems/t_bsd.pas

@@ -165,7 +165,11 @@ procedure TLinkerBSD.SetDefaultInfo;
 {
 {
   This will also detect which libc version will be used
   This will also detect which libc version will be used
 }
 }
+var
+  LdProgram: string='ld';
 begin
 begin
+  if target_info.system in systems_openbsd then
+    LdProgram:='ld.bfd';
   LibrarySuffix:=' ';
   LibrarySuffix:=' ';
   LdSupportsNoResponseFile := (target_info.system in ([system_m68k_netbsd]+systems_darwin));
   LdSupportsNoResponseFile := (target_info.system in ([system_m68k_netbsd]+systems_darwin));
   with Info do
   with Info do
@@ -174,8 +178,8 @@ begin
        begin
        begin
          if not(target_info.system in systems_darwin) then
          if not(target_info.system in systems_darwin) then
            begin
            begin
-             ExeCmd[1]:='ld $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -L. -o $EXE $CATRES $FILELIST';
-             DllCmd[1]:='ld $TARGET $EMUL $OPT $MAP $LTO $ORDERSYMS -shared -L. -o $EXE $CATRES $FILELIST'
+             ExeCmd[1]:=LdProgram+' $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -L. -o $EXE $CATRES $FILELIST';
+             DllCmd[1]:=LdProgram+' $TARGET $EMUL $OPT $MAP $LTO $ORDERSYMS -shared -L. -o $EXE $CATRES $FILELIST'
            end
            end
          else
          else
            begin
            begin
@@ -194,22 +198,22 @@ begin
                programs with problems that require Valgrind will have more
                programs with problems that require Valgrind will have more
                than 60KB of data (first 4KB of address space is always invalid)
                than 60KB of data (first 4KB of address space is always invalid)
              }
              }
-               ExeCmd[1]:='ld $PRTOBJ $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST';
+             ExeCmd[1]:=LdProgram+' $PRTOBJ $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST';
              if not(cs_gdb_valgrind in current_settings.globalswitches) then
              if not(cs_gdb_valgrind in current_settings.globalswitches) then
                ExeCmd[1]:=ExeCmd[1]+' -pagezero_size 0x10000';
                ExeCmd[1]:=ExeCmd[1]+' -pagezero_size 0x10000';
 {$else ndef cpu64bitaddr}
 {$else ndef cpu64bitaddr}
-             ExeCmd[1]:='ld $PRTOBJ $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST';
+             ExeCmd[1]:=LdProgram+' $PRTOBJ $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST';
 {$endif ndef cpu64bitaddr}
 {$endif ndef cpu64bitaddr}
              if (apptype<>app_bundle) then
              if (apptype<>app_bundle) then
-               DllCmd[1]:='ld $PRTOBJ $TARGET $EMUL $OPT $GCSECTIONS $MAP $LTO $ORDERSYMS -dynamic -dylib -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST'
+               DllCmd[1]:=LdProgram+' $PRTOBJ $TARGET $EMUL $OPT $GCSECTIONS $MAP $LTO $ORDERSYMS -dynamic -dylib -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST'
              else
              else
-               DllCmd[1]:='ld $PRTOBJ $TARGET $EMUL $OPT $GCSECTIONS $MAP $LTO $ORDERSYMS -dynamic -bundle -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST'
+               DllCmd[1]:=LdProgram+' $PRTOBJ $TARGET $EMUL $OPT $GCSECTIONS $MAP $LTO $ORDERSYMS -dynamic -bundle -multiply_defined suppress -L. -o $EXE $CATRES $FILELIST'
            end
            end
        end
        end
      else
      else
        begin
        begin
-         ExeCmd[1]:='ld $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -L. -o $EXE $RES';
-         DllCmd[1]:='ld $TARGET $EMUL $OPT $INIT $FINI $SONAME $MAP $LTO $ORDERSYMS -shared -L. -o $EXE $RES';
+         ExeCmd[1]:=LdProgram+' $TARGET $EMUL $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $ORDERSYMS -L. -o $EXE $RES';
+         DllCmd[1]:=LdProgram+' $TARGET $EMUL $OPT $INIT $FINI $SONAME $MAP $LTO $ORDERSYMS -shared -L. -o $EXE $RES';
        end;
        end;
      if not(target_info.system in systems_darwin) then
      if not(target_info.system in systems_darwin) then
        DllCmd[2]:='strip --strip-unneeded $EXE'
        DllCmd[2]:='strip --strip-unneeded $EXE'

+ 2 - 1
compiler/x86/rax86int.pas

@@ -2702,7 +2702,8 @@ Unit Rax86int;
               { convert 'call/jmp [proc/label]' to 'call/jmp proc/label'. Ugly,
               { convert 'call/jmp [proc/label]' to 'call/jmp proc/label'. Ugly,
                 but Turbo Pascal 7 compatible. }
                 but Turbo Pascal 7 compatible. }
               if (instr.opcode in [A_CALL,A_JMP]) and
               if (instr.opcode in [A_CALL,A_JMP]) and
-                 (instr.operands[i].haslabelref or instr.operands[i].hasproc)
+                 (instr.operands[i].haslabelref or instr.operands[i].hasproc) and
+                 (not instr.operands[i].hastype)
                  and (typ=OPR_REFERENCE) and
                  and (typ=OPR_REFERENCE) and
                  assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL,AT_ADDR]) and
                  assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL,AT_ADDR]) and
                  (ref.base=NR_NO) and (ref.index=NR_NO) then
                  (ref.base=NR_NO) and (ref.index=NR_NO) then

+ 1 - 0
packages/chm/fpmake.pp

@@ -31,6 +31,7 @@ begin
 
 
     D:=P.Dependencies.Add('fcl-xml');
     D:=P.Dependencies.Add('fcl-xml');
     D:=P.Dependencies.Add('fcl-base');
     D:=P.Dependencies.Add('fcl-base');
+    D:=P.Dependencies.Add('rtl-generics');
     D.Version:='3.3.1';
     D.Version:='3.3.1';
 
 
     P.SourcePath.Add('src');
     P.SourcePath.Add('src');

+ 2 - 3
packages/chm/src/chmcmd.lpr

@@ -145,7 +145,7 @@ begin
   else
   else
     begin
     begin
      try
      try
-      project.ScanHtmlContents:=htmlscan=scanforce;  // .hhp default SCAN
+      project.ScanHtmlContents:=htmlscan in [scanforce, scandefault];  // .hhp default SCAN
       Project.LoadFromFile(name);
       Project.LoadFromFile(name);
      except
      except
        on e:exception do
        on e:exception do
@@ -166,7 +166,6 @@ begin
     end;
     end;
   OutStream.Free;
   OutStream.Free;
   Project.Free;
   Project.Free;
-
 end;
 end;
 
 
 var
 var
@@ -178,7 +177,7 @@ var
 
 
 begin
 begin
   InitOptions;
   InitOptions;
-  Writeln(stderr,'chmcmd, a CHM compiler. (c) 2010 Free Pascal core.');
+  Writeln(stderr,'chmcmd, a CHM compiler. (c) 2010-2019 Free Pascal core.');
   Writeln(Stderr);
   Writeln(Stderr);
   repeat
   repeat
     c:=getlongopts('h',@theopts[1],optionindex);
     c:=getlongopts('h',@theopts[1],optionindex);

+ 237 - 84
packages/chm/src/chmfilewriter.pas

@@ -25,7 +25,7 @@ unit chmfilewriter;
 interface
 interface
 
 
 uses
 uses
-  Strings, Classes, SysUtils, chmwriter, inifiles, contnrs, chmsitemap, avl_tree,
+  Classes, SysUtils, chmwriter, inifiles, contnrs, chmsitemap, avl_tree,
   {for html scanning } dom,SAX_HTML,dom_html;
   {for html scanning } dom,SAX_HTML,dom_html;
 
 
 type
 type
@@ -68,7 +68,8 @@ type
     FIndex         : TCHMSiteMap;
     FIndex         : TCHMSiteMap;
     FTocStream,
     FTocStream,
     FIndexStream   : TMemoryStream;
     FIndexStream   : TMemoryStream;
-    FCores	   : integer;
+    FCores         : Integer;
+    FLocaleID      : Word;
   protected
   protected
     function GetData(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
     function GetData(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
     procedure LastFileAdded(Sender: TObject);
     procedure LastFileAdded(Sender: TObject);
@@ -84,6 +85,7 @@ type
     procedure LoadFromFile(AFileName: String); virtual;
     procedure LoadFromFile(AFileName: String); virtual;
     procedure LoadFromhhp (AFileName:String;LeaveInclude:Boolean); virtual;
     procedure LoadFromhhp (AFileName:String;LeaveInclude:Boolean); virtual;
     procedure SaveToFile(AFileName: String); virtual;
     procedure SaveToFile(AFileName: String); virtual;
+    procedure SaveToHHP(AFileName: String);
     procedure WriteChm(AOutStream: TStream); virtual;
     procedure WriteChm(AOutStream: TStream); virtual;
     procedure ShowUndefinedAnchors;
     procedure ShowUndefinedAnchors;
     function ProjectDir: String;
     function ProjectDir: String;
@@ -113,17 +115,16 @@ type
     property ScanHtmlContents  : Boolean read fScanHtmlContents write fScanHtmlContents;
     property ScanHtmlContents  : Boolean read fScanHtmlContents write fScanHtmlContents;
     property ReadmeMessage : String read FReadmeMessage write FReadmeMessage;
     property ReadmeMessage : String read FReadmeMessage write FReadmeMessage;
     property AllowedExtensions : TStringList read FAllowedExtensions;
     property AllowedExtensions : TStringList read FAllowedExtensions;
-    property Cores : integer read fcores write fcores; 
+    property Cores : integer read fcores write fcores;
+    property LocaleID: word read FLocaleID write FLocaleID;
   end;
   end;
 
 
   TChmContextNode = Class
   TChmContextNode = Class
                      URLName       : AnsiString;
                      URLName       : AnsiString;
-                     ContextNumber : Integer;
+                     ContextNumber : THelpContext;
                      ContextName   : AnsiString;
                      ContextName   : AnsiString;
                     End;
                     End;
 
 
-
-
 Const
 Const
   ChmErrorKindText : array[TCHMProjectErrorKind] of string = ('Error','Warning','Hint','Note','');
   ChmErrorKindText : array[TCHMProjectErrorKind] of string = ('Error','Warning','Hint','Note','');
 
 
@@ -272,6 +273,23 @@ begin
     inc(result);
     inc(result);
 end;
 end;
 
 
+// hex codes of LCID (Locale IDs) see at http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx
+function GetLanguageID(const sValue: String): word;
+const
+  DefaultLCID = $0409; // default "English - United States", 0x0409
+var
+  ACode: word;
+begin
+  Result := DefaultLCID;
+  if Length(sValue) >= 5 then
+  begin
+    Val(Trim(Copy(sValue, 1, 6)), Result, ACode);
+    //if Code <> 0 then
+    //Result := DefaultLCID;
+  end
+end;
+
+
 procedure TChmProject.readIniOptions(keyvaluepairs:tstringlist);
 procedure TChmProject.readIniOptions(keyvaluepairs:tstringlist);
 var i : integer;
 var i : integer;
     Opt : TOptionEnum;
     Opt : TOptionEnum;
@@ -308,7 +326,7 @@ begin
       OPTFULL_TEXT_SEARCH          : MakeSearchable:=optvalupper='YES';
       OPTFULL_TEXT_SEARCH          : MakeSearchable:=optvalupper='YES';
       OPTIGNORE                    : ;
       OPTIGNORE                    : ;
       OPTINDEX_FILE                : Indexfilename:=optval;
       OPTINDEX_FILE                : Indexfilename:=optval;
-      OPTLANGUAGE                  : ;
+      OPTLANGUAGE                  : LocaleID := GetLanguageID(optval);
       OPTPREFIX                    : ;  // doesn't seem to have effect
       OPTPREFIX                    : ;  // doesn't seem to have effect
       OPTSAMPLE_STAGING_PATH       : ;
       OPTSAMPLE_STAGING_PATH       : ;
       OPTSAMPLE_LIST_FILE          : ;
       OPTSAMPLE_LIST_FILE          : ;
@@ -401,6 +419,7 @@ begin
   DefaultFont  := Cfg.GetValue('Settings/DefaultFont/Value', '');
   DefaultFont  := Cfg.GetValue('Settings/DefaultFont/Value', '');
   DefaultWindow:= Cfg.GetValue('Settings/DefaultWindow/Value', '');
   DefaultWindow:= Cfg.GetValue('Settings/DefaultWindow/Value', '');
   ScanHtmlContents:=  Cfg.GetValue('Settings/ScanHtmlContents/Value', False);
   ScanHtmlContents:=  Cfg.GetValue('Settings/ScanHtmlContents/Value', False);
+  LocaleID := Cfg.GetValue('Settings/LocaleID/Value', $0409);
 
 
   Cfg.Free;
   Cfg.Free;
 end;
 end;
@@ -698,7 +717,7 @@ begin
 
 
   Cfg.SetValue('Settings/DefaultWindow/Value', DefaultWindow);
   Cfg.SetValue('Settings/DefaultWindow/Value', DefaultWindow);
   Cfg.SetValue('Settings/ScanHtmlContents/Value', ScanHtmlContents);
   Cfg.SetValue('Settings/ScanHtmlContents/Value', ScanHtmlContents);
-
+  Cfg.SetValue('Settings/LocaleID/Value', LocaleID);
 
 
   Cfg.Flush;
   Cfg.Flush;
   Cfg.Free;
   Cfg.Free;
@@ -742,16 +761,19 @@ begin
 
 
    i:=pos('#',outstring);
    i:=pos('#',outstring);
    if i<>0 then begin
    if i<>0 then begin
-     if i > 1 then
-       Anchor := outstring
-     else
-       Anchor := localname+outstring;
-     j := fAnchorList.IndexOf(Anchor);
-     if j < 0 then begin
-       fAnchorList.AddObject(Anchor,TFirstReference.Create(localname));
-       Anchor := '(new) '+Anchor;
-     end;
-     Error(CHMNote, 'Anchor found '+Anchor+' while scanning '+localname,1);
+     if i<>length(outstring) then // trims lone '#' at end of url.
+       begin
+         if i > 1 then
+           Anchor := outstring
+         else
+           Anchor := localname+outstring;
+         j := fAnchorList.IndexOf(Anchor);
+         if j < 0 then begin
+           fAnchorList.AddObject(Anchor,TFirstReference.Create(localname));
+           Anchor := '(new) '+Anchor;
+         end;
+         Error(CHMNote, 'Anchor found '+Anchor+' while scanning '+localname,1);
+       end;
      delete(outstring,i,length(outstring)-i+1);
      delete(outstring,i,length(outstring)-i+1);
    end;
    end;
 
 
@@ -759,6 +781,8 @@ begin
 
 
   outstring:=extractrelativepath(basepath,outstring);
   outstring:=extractrelativepath(basepath,outstring);
   outstring:=StringReplace(outstring,'\','/',[rfReplaceAll]);
   outstring:=StringReplace(outstring,'\','/',[rfReplaceAll]);
+  if outstring='' then
+    result:=false;
 end;
 end;
 
 
 function  TChmProject.FileInTotalList(const s:String):boolean;
 function  TChmProject.FileInTotalList(const s:String):boolean;
@@ -808,13 +832,55 @@ begin
       filelist.add(fn);
       filelist.add(fn);
 end;
 end;
 
 
+procedure checkattributesA(node:TDomNode;const localname: string; filelist :TStringList);
+// workaround for "a" tag that has href and src. If src exists, don't check href, this
+// avoids spurious warnings.
+var
+    fn  : String;
+    val : String;
+    found : boolean;
+begin
+  found:=false;
+  val := findattribute(node,'SRC');
+  if sanitizeurl(fbasepath,val,localpath,localname,fn) then
+      found:=true;
+  if not found then
+    begin
+      val := findattribute(node,'HREF');
+      if sanitizeurl(fbasepath,val,localpath,localname,fn) then
+        found:=true;
+    end;
+ if found and not FileInTotalList(uppercase(fn)) then
+      filelist.add(fn);
+end;
 
 
 function scantags(prnt:TDomNode; const localname: string; filelist:TStringlist):TDomNode;
 function scantags(prnt:TDomNode; const localname: string; filelist:TStringlist):TDomNode;
-// Seach first matching tag in siblings
+
+var
+  att : ansistring;
+
+procedure AddAnchor(const s:string);
+var
+   i   : Integer;
+begin
+  i := fAnchorList.IndexOf(localname+'#'+s);
+  if i < 0 then begin
+    fAnchorList.Add(localname+'#'+s);
+    Error(ChmNote,'New Anchor with '+att+' '+s+' found while scanning '+localname,1);
+  end else if fAnchorList.Objects[i] = nil then
+    Error(chmwarning,'Duplicate anchor definitions with '+att+' '+s+' found while scanning '+localname,1)
+  else begin
+    fAnchorList.Objects[i].Free;
+    fAnchorList.Objects[i] := nil;
+    Error(ChmNote,'Anchor with '+att+' '+s+' defined while scanning '+localname,1);
+  end;
+end;
+
 var chld: TDomNode;
 var chld: TDomNode;
-    s,
-    att : ansistring;
-    i   : Integer;
+    s,attrval  : ansistring;
+    idfound : boolean;
+
+
 begin
 begin
   result:=nil;
   result:=nil;
   if assigned(prnt )  then
   if assigned(prnt )  then
@@ -826,6 +892,11 @@ begin
           if (chld is TDomElement) then
           if (chld is TDomElement) then
             begin
             begin
               s:=uppercase(tdomelement(chld).tagname);
               s:=uppercase(tdomelement(chld).tagname);
+              att := 'ID';
+              attrval := findattribute(chld, att);
+              idfound:=attrval  <> '' ;
+              if idfound then
+                addanchor(attrval);
               if s='LINK' then
               if s='LINK' then
                 begin
                 begin
                   //printattributes(chld,'');
                   //printattributes(chld,'');
@@ -836,34 +907,21 @@ begin
                   //printattributes(chld,'');
                   //printattributes(chld,'');
                   checkattributes(chld,'SRC',localname,filelist);
                   checkattributes(chld,'SRC',localname,filelist);
                 end;
                 end;
-             if s='IMG'then
+             if s='IMG' then
                begin
                begin
                   //printattributes(chld,'');
                   //printattributes(chld,'');
                   checkattributes(chld,'SRC',localname,filelist);
                   checkattributes(chld,'SRC',localname,filelist);
                end;
                end;
-             if s='A'then
+             if s='A' then
                begin
                begin
                   //printattributes(chld,'');
                   //printattributes(chld,'');
-                  checkattributes(chld,'HREF',localname,filelist);
-                  att := 'NAME';
-                  s := findattribute(chld, att);
-                  if s = '' then begin
-                     att := 'ID';
-                     s := findattribute(chld, att);
-                  end;
-                  if s <> '' then
+                  checkattributesA(chld,localname,filelist);
+                  if not idfound then
                     begin
                     begin
-                      i := fAnchorList.IndexOf(localname+'#'+s);
-                      if i < 0 then begin
-                        fAnchorList.Add(localname+'#'+s);
-                        Error(ChmNote,'New Anchor with '+att+' '+s+' found while scanning '+localname,1);
-                      end else if fAnchorList.Objects[i] = nil then
-                        Error(chmwarning,'Duplicate anchor definitions with '+att+' '+s+' found while scanning '+localname,1)
-                      else begin
-                        fAnchorList.Objects[i].Free;
-                        fAnchorList.Objects[i] := nil;
-                        Error(ChmNote,'Anchor with '+att+' '+s+' defined while scanning '+localname,1);
-                      end;
+                      att := 'NAME';
+                      attrval := findattribute(chld, att);
+                      if attrval  <> '' then
+                       addanchor(attrval);
                     end;
                     end;
                 end;
                 end;
             end;
             end;
@@ -876,11 +934,8 @@ var
   localfilelist: TStringList;
   localfilelist: TStringList;
   domdoc : THTMLDocument;
   domdoc : THTMLDocument;
   i,j    : Integer;
   i,j    : Integer;
-  fn,s   : string;
-  ext    : String;
+  fn,reffn   : string;
   tmplst : Tstringlist;
   tmplst : Tstringlist;
-  strrec : TStringIndex;
-  //localpath : string;
 
 
 function trypath(const vn:string):boolean;
 function trypath(const vn:string):boolean;
 var vn2: String;
 var vn2: String;
@@ -926,10 +981,9 @@ begin
                scantags(domdoc,extractfilename(fn),localfilelist);
                scantags(domdoc,extractfilename(fn),localfilelist);
                for i:=0 to localFilelist.count-1 do
                for i:=0 to localFilelist.count-1 do
                  begin
                  begin
-                   s:=localfilelist[i];
-                   if not trypath(s) then
-//                     if not trypath(localpath+s) then
-                       Error(ChmWarning,'Found file '+s+' while scanning '+fn+', but couldn''t find it on disk',2);
+                   reffn:=localfilelist[i];
+                   if not trypath(reffn) then  //  if not trypath(localpath+s) then
+                       Error(ChmWarning,'Found file '+reffn+' while scanning '+fn+', but couldn''t find it on disk',2);
                  end;
                  end;
              except
              except
                on e:EDomError do
                on e:EDomError do
@@ -952,15 +1006,14 @@ begin
 
 
            for i:=0 to tmplst.Count-1 do
            for i:=0 to tmplst.Count-1 do
              begin
              begin
-               s:=tmplst[i];
-               if pos('url(''', tmplst[i])>0 then
+               reffn:=tmplst[i];
+               if pos('url(''', reffn)>0 then
                  begin
                  begin
-                   delete(s,1,pos('url(''', tmplst[i])+4);
-                   s:=trim(copy(s,1,pos('''',s)-1));
-
-                   if not trypath(s) then
+                   delete(reffn,1,pos('url(''', reffn)+4);
+                   reffn:=trim(copy(reffn,1,pos('''',reffn)-1));
+                   if not trypath(reffn) then
 //                     if not trypath(localpath+s) then
 //                     if not trypath(localpath+s) then
-                       Error(ChmWarning,'Found file '+s+' while scanning '+fn+', but couldn''t find it on disk',2);
+                       Error(ChmWarning,'Found file '+reffn+' while scanning '+fn+', but couldn''t find it on disk',2);
                  end;
                  end;
              end;
              end;
          finally
          finally
@@ -984,8 +1037,9 @@ procedure TChmProject.ScanSitemap(sitemap:TChmSiteMap;newfiles:TStrings;recursio
 
 
 procedure scanitems(it:TChmSiteMapItems);
 procedure scanitems(it:TChmSiteMapItems);
 
 
-var i : integer;
+var i,j : integer;
     x : TChmSiteMapItem;
     x : TChmSiteMapItem;
+    si  : TChmSiteMapSubItem;
     s : string;
     s : string;
     strrec : TStringIndex;
     strrec : TStringIndex;
 
 
@@ -993,34 +1047,37 @@ begin
   for i:=0 to it.count -1 do
   for i:=0 to it.count -1 do
     begin
     begin
       x:=it.item[i];
       x:=it.item[i];
-      if sanitizeurl(fbasepath,x.local,'','Site Map for '+x.Text,S) then   // sanitize, remove stuff etc.
-        begin
-          if not FileInTotalList(uppercase(s)) then
-            begin
-              if fileexists(s) then
-                begin
-                  Error(chmnote,'Good url: '+s+'.',5);
-                  StrRec:=TStringIndex.Create;
-                  StrRec.TheString:=uppercase(s);
-                  StrRec.Strid    :=0;
-                  fTotalFileList.Add(StrRec);
-                  newfiles.add(s);
-                end
-              else
-                Error(chmnote,'duplicate url: '+s+'.',5);
-            end
-          else
-            Error(chmnote,'duplicate url: '+s+'.',5);
-        end
-      else
-       Error(chmnote,'Bad url: '+s+'.',5);
-
+      for j:=0 to x.SubItemcount-1 do
+         begin
+           si:=x.SubItem[j];
+           if sanitizeurl(fbasepath,si.local,'','Site Map for '+x.Text,S) then   // sanitize, remove stuff etc.
+             begin
+               if not FileInTotalList(uppercase(s)) then
+                 begin
+                   if fileexists(s) then
+                     begin
+                       Error(chmnote,'Good url: '+s+'.',5);
+                       StrRec:=TStringIndex.Create;
+                       StrRec.TheString:=uppercase(s);
+                       StrRec.Strid    :=0;
+                       fTotalFileList.Add(StrRec);
+                       newfiles.add(s);
+                     end
+                   else
+                     Error(chmnote,'duplicate url: '+s+'.',5);
+                 end
+               else
+                 Error(chmnote,'duplicate url: '+s+'.',5);
+             end
+           else
+            Error(chmnote,'Bad url: '+s+'.',5);
+         end;
       if assigned(x.children) and (x.children.count>0) then
       if assigned(x.children) and (x.children.count>0) then
         scanitems(x.children);
         scanitems(x.children);
     end;
     end;
 end;
 end;
 
 
-var i : integer;
+var
     localfilelist: TStringList;
     localfilelist: TStringList;
 
 
 begin
 begin
@@ -1137,6 +1194,7 @@ begin
   Writer.TocName   := ExtractFileName(TableOfContentsFileName);
   Writer.TocName   := ExtractFileName(TableOfContentsFileName);
   Writer.ReadmeMessage := ReadmeMessage;
   Writer.ReadmeMessage := ReadmeMessage;
   Writer.DefaultWindow := FDefaultWindow;
   Writer.DefaultWindow := FDefaultWindow;
+  Writer.LocaleID := FLocaleID;
   for i:=0 to files.count-1 do
   for i:=0 to files.count-1 do
     begin
     begin
       nd:=TChmContextNode(files.objects[i]);
       nd:=TChmContextNode(files.objects[i]);
@@ -1169,7 +1227,7 @@ var
 begin
 begin
   for i := 0 to fAnchorList.Count-1 do
   for i := 0 to fAnchorList.Count-1 do
     if fAnchorList.Objects[i] <> nil then
     if fAnchorList.Objects[i] <> nil then
-      Error(chmerror,'Anchor '+fAnchorList[i]+' undefined; first use '+TFirstReference(fAnchorList.Objects[i]).Location);
+       Error(chmerror,'Anchor '+fAnchorList[i]+' undefined; first use '+TFirstReference(fAnchorList.Objects[i]).Location);
 end;
 end;
 
 
 procedure TChmProject.LoadSitemaps;
 procedure TChmProject.LoadSitemaps;
@@ -1188,7 +1246,6 @@ begin
            FreeAndNil(FToc);
            FreeAndNil(FToc);
            FToc:=TChmSiteMap.Create(sttoc);
            FToc:=TChmSiteMap.Create(sttoc);
            FToc.loadfromstream(FTocStream);
            FToc.loadfromstream(FTocStream);
-           ftoc.savetofile('bla.something');
          except
          except
           on e:exception do
           on e:exception do
             begin
             begin
@@ -1227,5 +1284,101 @@ begin
 end;
 end;
 
 
 
 
+function BoolAsStr(b: Boolean): string;
+begin
+  if b then
+    Result := 'Yes'
+  else
+    Result := 'No';
+end;
+
+procedure TChmProject.SaveToHHP(AFileName: String);
+var
+  sl: TStringList;
+  s : string;
+  i: Integer;
+  ContextItem: TChmContextNode;
+
+  procedure SetOption(const AKey, AValue: string);
+  begin
+    if AValue <> '' then
+      sl.Add(AKey + '=' + AValue);
+  end;
+
+begin
+  sl := TStringList.Create();
+  try
+    sl.Add('[OPTIONS]');
+    SetOption('Title', Title);
+    SetOption('Compatibility', '1.1 or later');
+    SetOption('Compiled file', OutputFileName);
+    SetOption('Default Topic', DefaultPage);
+    SetOption('Default Font', DefaultFont);
+    SetOption('Default Window', DefaultWindow);
+    SetOption('Display compile progress', 'Yes');
+    //SetOption('Error log file', 'errors.log');
+    SetOption('Contents file', TableOfContentsFileName);
+    //SetOption('Auto Index', BoolAsStr(MakeBinaryIndex));
+    SetOption('Index file', IndexFileName);
+    SetOption('Binary Index', BoolAsStr(MakeBinaryIndex));
+    SetOption('Binary TOC', BoolAsStr(MakeBinaryTOC));
+    SetOption('Full-text search', BoolAsStr(MakeSearchable));
+    SetOption('Language', '0x' + IntToHex(LocaleID, 4));
+
+    sl.Add('');
+    sl.Add('[FILES]');
+    for i := 0 to Files.Count - 1 do
+    begin
+      s := StringReplace(Files.Strings[i], '/', '\', [rfReplaceAll]);
+      sl.Add(s);
+    end;
+
+    if MergeFiles.Count > 0 then
+    begin
+      sl.Add('');
+      sl.Add('[MERGE FILES]');
+      for i := 0 to MergeFiles.Count - 1 do
+      begin
+        sl.Add(MergeFiles.Strings[i]);
+      end;
+    end;
+
+    if Windows.Count > 0 then
+    begin
+      sl.Add('');
+      sl.Add('[WINDOWS]');
+      for i := 0 to Windows.Count-1 do
+      begin
+        TCHMWindow(Windows[i]).SaveToIni(s);
+        sl.Add(s);
+      end;
+    end;
+
+    if Files.Count > 0 then
+    begin
+      sl.Add('');
+      sl.Add('[ALIAS]');
+      for i := 0 to Files.Count - 1 do
+      begin
+        contextitem:=TChmContextNode(files.objects[i]);
+        if assigned(contextitem) then
+          sl.Add(ContextItem.ContextName + '=' + ContextItem.UrlName);
+      end;
+
+      sl.Add('');
+      sl.Add('[MAP]');
+      for I := 0 to Files.Count-1 do
+      begin
+        contextitem:=TChmContextNode(files.objects[i]);
+        if assigned(contextitem) then
+          sl.Add('#define ' + ContextItem.ContextName + ' ' + IntToStr(ContextItem.ContextNumber));
+      end;
+    end;
+
+    sl.SaveToFile(AFileName);
+  finally
+    sl.Free();
+  end;
+end;
 end.
 end.
 
 

+ 185 - 97
packages/chm/src/chmreader.pas

@@ -20,15 +20,17 @@
 }
 }
 unit chmreader;
 unit chmreader;
 
 
-{$mode objfpc}{$H+}
+{$mode delphi}
 
 
 //{$DEFINE CHM_DEBUG}
 //{$DEFINE CHM_DEBUG}
 { $DEFINE CHM_DEBUG_CHUNKS}
 { $DEFINE CHM_DEBUG_CHUNKS}
-
+{define binindex}
+{define nonumber}
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, Contnrs, chmbase, paslzx, chmFIftiMain, chmsitemap;
+  Generics.Collections, Classes, SysUtils,  Contnrs,
+  chmbase, paslzx, chmFIftiMain, chmsitemap;
 
 
 type
 type
 
 
@@ -729,7 +731,7 @@ var
   PMGIndex: Integer;
   PMGIndex: Integer;
   {$ENDIF}
   {$ENDIF}
 begin
 begin
-  if ForEach = nil then Exit;
+  if not assigned(ForEach) then Exit;
   ChunkStream := TMemoryStream.Create;
   ChunkStream := TMemoryStream.Create;
   {$IFDEF CHM_DEBUG_CHUNKS}
   {$IFDEF CHM_DEBUG_CHUNKS}
   WriteLn('ChunkCount = ',fDirectoryHeader.DirectoryChunkCount);
   WriteLn('ChunkCount = ',fDirectoryHeader.DirectoryChunkCount);
@@ -970,6 +972,12 @@ begin
     fTOPICSStream.ReadDWord;
     fTOPICSStream.ReadDWord;
     TopicTitleOffset := LEtoN(fTOPICSStream.ReadDWord);
     TopicTitleOffset := LEtoN(fTOPICSStream.ReadDWord);
     TopicURLTBLOffset := LEtoN(fTOPICSStream.ReadDWord);
     TopicURLTBLOffset := LEtoN(fTOPICSStream.ReadDWord);
+    {$ifdef binindex}
+    {$ifndef nonumber}
+    writeln('titleid:',TopicTitleOffset);
+    writeln('urlid  :',TopicURLTBLOffset);
+    {$endif}
+    {$endif}
     if TopicTitleOffset <> $FFFFFFFF then
     if TopicTitleOffset <> $FFFFFFFF then
       ATitle := ReadStringsEntry(TopicTitleOffset);
       ATitle := ReadStringsEntry(TopicTitleOffset);
      //WriteLn('Got a title: ', ATitle);
      //WriteLn('Got a title: ', ATitle);
@@ -1016,7 +1024,10 @@ begin
   result:=head<tail;
   result:=head<tail;
 
 
   n:=head-oldhead;
   n:=head-oldhead;
-  if (n>0) and (oldhead[n-1]=0) then dec(n); // remove trailing #0
+
+  pw:=pword(@oldhead[n]);
+  if (n>1) and (pw[-1]=0) then
+    dec(n,2); // remove trailing #0
   setlength(ws,n div sizeof(widechar));
   setlength(ws,n div sizeof(widechar));
   move(oldhead^,ws[1],n);
   move(oldhead^,ws[1],n);
   for n:=1 to length(ws) do
   for n:=1 to length(ws) do
@@ -1024,10 +1035,15 @@ begin
   readv:=ws; // force conversion for now, and hope it doesn't require cwstring
   readv:=ws; // force conversion for now, and hope it doesn't require cwstring
 end;
 end;
 
 
+
+Type TLookupRec = record
+                   item : TChmSiteMapItems;
+                   depth : integer;
+                   end;
+     TLookupDict = TDictionary<string,TLookupRec>;
 function TChmReader.GetIndexSitemap(ForceXML:boolean=false): TChmSiteMap;
 function TChmReader.GetIndexSitemap(ForceXML:boolean=false): TChmSiteMap;
 var Index   : TMemoryStream;
 var Index   : TMemoryStream;
-    sitemap : TChmSiteMap;
-    Item    : TChmSiteMapItem;
+
 
 
 function  AbortAndTryTextual:tchmsitemap;
 function  AbortAndTryTextual:tchmsitemap;
 
 
@@ -1045,76 +1061,48 @@ begin
       result:=nil;
       result:=nil;
 end;
 end;
 
 
-procedure createentry(Name:ansistring;CharIndex:integer;Topic,Title:ansistring);
-var litem : TChmSiteMapItem;
-    shortname : ansistring;
-    longpart  : ansistring;
-begin
- if charindex=0 then
-   begin
-     item:=sitemap.items.NewItem;
-     item.keyword:=Name;
-     item.local:=topic;
-     item.text:=title;
-   end
- else
-   begin
-     shortname:=copy(name,1,charindex-2);
-     longpart:=copy(name,charindex,length(name)-charindex+1);
-     if assigned(item) and (shortname=item.text) then
-       begin
-         litem:=item.children.newitem;
-         litem.local:=topic;
-         litem.keyword :=longpart; // recursively split this? No examples.
-         litem.text:=title;
-       end
-      else
-       begin
-         item:=sitemap.items.NewItem;
-         item.keyword:=shortname;
-         item.local:=topic;
-         item.text:=title;
-         litem:=item.children.newitem;
-         litem.keyword:=longpart;
-         litem.local:=topic;
-         litem.text :=Title; // recursively split this? No examples.
-       end;
-   end;
-end;
+var
+   parentitem:TChmSiteMapItems;
+   itemstack :TObjectList;
+   lookup  : TLookupDict;
+   curitemdepth : integer;
+   sitemap : TChmSiteMap;
 
 
-procedure createentryseealso(Name:ansistring;CharIndex:integer;seealso:ansistring);
-var litem : TChmSiteMapItem;
+function getitem(anentrydepth:integer):Tchmsitemapitems;
 begin
 begin
-     item:=sitemap.items.NewItem;
-     item.KeyWord:=name;
-     item.SeeAlso:=seealso;
+   if anentrydepth<itemstack.count then
+     result:=tchmsitemapitems(itemstack[anentrydepth])
+   else
+     begin
+       {$ifdef binindex}
+         writeln('pop from emptystack at ',anentrydepth,' ',itemstack.count);
+       {$endif}
+       result:=tchmsitemapitems(itemstack[itemstack.Count-1]);
+     end;
 end;
 end;
 
 
+procedure pushitem(anentrydepth:integer;anitem:tchmsitemapitem);
+begin
 
 
+ if anentrydepth<itemstack.count then
+   itemstack[anentrydepth]:=anitem.children
+ else
+   if anentrydepth=itemstack.count then
+     itemstack.add(anitem.Children)
+   else
+     begin
+       {$ifdef binindex}
+         writeln('push more than 1 larger ' ,anentrydepth,' ',itemstack.count);
+       {$endif}
+       itemstack.add(anitem.Children)
+     end;
+end;
 procedure parselistingblock(p:pbyte);
 procedure parselistingblock(p:pbyte);
 var
 var
-    itemstack:TObjectStack;
-    curitemdepth : integer;
-    parentitem:TChmSiteMap;
 
 
-procedure updateparentitem(entrydepth:integer);
-begin
-  if entrydepth>curitemdepth then
-    begin
-      if curitemdepth<>0 then
-        itemstack.push(parentitem);
-      curitemdepth:=entrydepth;
-    end
-  else
-   if entrydepth>curitemdepth then
-    begin
-      if curitemdepth<>0 then
-        itemstack.push(parentitem);
-      curitemdepth:=entrydepth;
-    end
-end;
+    Item    : TChmSiteMapItem;
 
 
-var hdr:PBTreeBlockHeader;
+    hdr:PBTreeBlockHeader;
     head,tail : pbyte;
     head,tail : pbyte;
     isseealso,
     isseealso,
     entrydepth,
     entrydepth,
@@ -1125,8 +1113,41 @@ var hdr:PBTreeBlockHeader;
     CharIndex,
     CharIndex,
     ind:integer;
     ind:integer;
     seealsostr,
     seealsostr,
-    topic,
+    s,
     Name : AnsiString;
     Name : AnsiString;
+    path,
+    shortname : AnsiString;
+    anitem:TChmSiteMapItems;
+    litem : TChmSiteMapItem;
+    lookupitem : TLookupRec;
+
+function readvalue:string;
+begin
+  if head<tail Then
+    begin
+      ind:=LEToN(plongint(head)^);
+
+      result:=lookuptopicbyid(ind,title);
+      {$ifdef binindex}
+        writeln(i:3,' topic: ' {$ifndef nonumber},'  (',ind,')' {$endif});
+        writeln('    title: ',title);
+        writeln('    result: ',result);
+      {$endif}
+      inc(head,4);
+    end;
+end;
+
+procedure dumpstack;
+var fp : TChmSiteMapItems;
+     ix : Integer;
+begin
+  for ix:=0 to itemstack.Count-1 do
+    begin
+      fp :=TChmSiteMapItems(itemstack[ix]);
+      writeln(ix:3,' ',fp.parentname);
+    end;
+end;
+
 begin
 begin
   //setlength (curitem,10);
   //setlength (curitem,10);
   hdr:=PBTreeBlockHeader(p);
   hdr:=PBTreeBlockHeader(p);
@@ -1135,17 +1156,21 @@ begin
   hdr^.IndexOfPrevBlock:=LEToN(hdr^.IndexOfPrevBlock);
   hdr^.IndexOfPrevBlock:=LEToN(hdr^.IndexOfPrevBlock);
   hdr^.IndexOfNextBlock:=LEToN(hdr^.IndexOfNextBlock);
   hdr^.IndexOfNextBlock:=LEToN(hdr^.IndexOfNextBlock);
 
 
+  {$ifdef binindex}
+  writeln('hdr:',hdr^.length);
+  {$endif}
   tail:=p+(2048-hdr^.length);
   tail:=p+(2048-hdr^.length);
   head:=p+sizeof(TBtreeBlockHeader);
   head:=p+sizeof(TBtreeBlockHeader);
 
 
-  itemstack:=TObjectStack.create;
   {$ifdef binindex}
   {$ifdef binindex}
+  {$ifndef nonumber}
   writeln('previndex  : ',hdr^.IndexOfPrevBlock);
   writeln('previndex  : ',hdr^.IndexOfPrevBlock);
   writeln('nextindex  : ',hdr^.IndexOfNextBlock);
   writeln('nextindex  : ',hdr^.IndexOfNextBlock);
   {$endif}
   {$endif}
-  curitemdepth:=0;
+  {$endif}
   while head<tail do
   while head<tail do
     begin
     begin
+      //writeln(tail-head);
       if not ReadWCharString(Head,Tail,Name) Then
       if not ReadWCharString(Head,Tail,Name) Then
         Break;
         Break;
       {$ifdef binindex}
       {$ifdef binindex}
@@ -1158,6 +1183,75 @@ begin
       IsSeealso:=LEToN(PE^.isseealso);
       IsSeealso:=LEToN(PE^.isseealso);
       EntryDepth:=LEToN(PE^.entrydepth);
       EntryDepth:=LEToN(PE^.entrydepth);
       CharIndex:=LEToN(PE^.CharIndex);
       CharIndex:=LEToN(PE^.CharIndex);
+      Path:='';
+
+      if charindex<>0 then
+        begin
+          Path:=Trim(Copy(Name,1,charindex-2));
+          Shortname:=trim(copy(Name,charindex,Length(Name)-Charindex+1));
+        end
+      else
+        shortname:=name;
+      {$ifdef binindex}
+      writeln('depth:', curitemdepth, ' ' ,entrydepth);
+      {$endif}
+      if curitemdepth=entrydepth then // same level, so of same parent
+         begin
+           item:=parentitem.newitem;
+           pushitem(entrydepth+1,item);
+         end
+      else
+        if curitemdepth=entrydepth-1 then // new child, one lower.
+          begin
+            parentitem:=getitem(entrydepth);
+            item:=parentitem.newitem;
+            pushitem(entrydepth+1,item);
+          end
+        else
+         if entrydepth<curitemdepth then
+          begin
+            parentitem:=getitem(entrydepth);
+            {$ifdef binindex}
+            writeln('bingo!', parentitem.parentname);
+            dumpstack;
+            {$endif}
+            item:=parentitem.newitem;
+            pushitem(entrydepth+1,item);
+          end;
+
+      curitemdepth:=entrydepth;
+      {$ifdef binindex}
+      writeln('lookup:', Name, ' = ', path,' = ',shortname);
+      {$endif}
+
+    (*  if lookup.trygetvalue(path,lookupitem) then
+        begin
+//          if lookupitem.item<>parentitem then
+//             writeln('mismatch: ',lookupitem.item.item[0].name,' ',name);
+{          if curitemdepth<entrydepth then
+            begin
+              writeln('lookup ok!',curitemdepth,' ' ,entrydepth);
+              curitemdepth:=entrydepth;
+            end
+          else
+           begin
+             writeln('lookup odd!',curitemdepth,' ' ,entrydepth);
+           end;
+          curitemdepth:=lookupitem.depth+1;
+          parentitem:=lookupitem.item;}
+        end
+      else
+        begin
+ //            parentitem:=sitemap.Items;
+          if not curitemdepth=entrydepth then
+             writeln('no lookup odd!',curitemdepth,' ' ,entrydepth);
+        end;  *)
+{      item:=parentitem.newitem;}
+      lookupitem.item:=item.children;
+      lookupitem.depth:=entrydepth;
+      lookup.addorsetvalue(name,lookupitem);
+      item.AddName(Shortname);
+
       {$ifdef binindex}
       {$ifdef binindex}
         Writeln('seealso   :  ',IsSeeAlso);
         Writeln('seealso   :  ',IsSeeAlso);
         Writeln('entrydepth:  ',EntryDepth);
         Writeln('entrydepth:  ',EntryDepth);
@@ -1178,7 +1272,7 @@ begin
           {$ifdef binindex}
           {$ifdef binindex}
             writeln('seealso: ',seealsostr);
             writeln('seealso: ',seealsostr);
           {$endif}
           {$endif}
-
+          item.AddSeeAlso(seealsostr);
         end
         end
       else
       else
         begin
         begin
@@ -1190,24 +1284,13 @@ begin
 
 
             for i:=0 to nrpairs-1 do
             for i:=0 to nrpairs-1 do
               begin
               begin
-                if head<tail Then
-                  begin
-                    ind:=LEToN(plongint(head)^);
-                    topic:=lookuptopicbyid(ind,title);
-                    {$ifdef binindex}
-                      writeln(i:3,' topic: ',topic);
-                      writeln('    title: ',title);
-                    {$endif}
-                    inc(head,4);
-                  end;
+               s:=readvalue;
+             //  if not ((i=0) and (title=shortname)) then
+               item.addname(title);
+               item.addlocal(s);
               end;
               end;
           end;
           end;
          end;
          end;
-      if isseealso>0 then
-         createentryseealso(name,charindex,seealsostr)
-      else
-        if nrpairs<>0 Then
-          createentry(Name,CharIndex,Topic,Title);
       inc(head,4); // always 1
       inc(head,4); // always 1
       {$ifdef binindex}
       {$ifdef binindex}
         if head<tail then
         if head<tail then
@@ -1215,15 +1298,16 @@ begin
       {$endif}
       {$endif}
       inc(head,4); // zero based index (13 higher than last
       inc(head,4); // zero based index (13 higher than last
     end;
     end;
-  ItemStack.Free;
 end;
 end;
 
 
 var TryTextual : boolean;
 var TryTextual : boolean;
     BHdr       : TBTreeHeader;
     BHdr       : TBTreeHeader;
     block      : Array[0..2047] of Byte;
     block      : Array[0..2047] of Byte;
     i          : Integer;
     i          : Integer;
+
 begin
 begin
    Result := nil;  SiteMap:=Nil;
    Result := nil;  SiteMap:=Nil;
+   lookup:=TDictionary<string,TLookupRec>.create;
    // First Try Binary
    // First Try Binary
    Index := GetObject('/$WWKeywordLinks/BTree');
    Index := GetObject('/$WWKeywordLinks/BTree');
    if (Index = nil) or ForceXML then
    if (Index = nil) or ForceXML then
@@ -1237,9 +1321,12 @@ begin
      Exit;
      Exit;
    end;
    end;
    SiteMap:=TChmSitemap.Create(StIndex);
    SiteMap:=TChmSitemap.Create(StIndex);
-   Item   :=Nil;  // cached last created item, in case we need to make
+   itemstack :=TObjectList.create(false);
+   //Item   :=Nil;  // cached last created item, in case we need to make
                   // a child.
                   // a child.
-
+   parentitem:=sitemap.Items;
+   itemstack.add(parentitem); // level 0
+   curitemdepth:=0;
    TryTextual:=True;
    TryTextual:=True;
    BHdr.LastLstBlock:=0;
    BHdr.LastLstBlock:=0;
    if LoadBtreeHeader(index,BHdr) and (BHdr.LastLstBlock>=0) Then
    if LoadBtreeHeader(index,BHdr) and (BHdr.LastLstBlock>=0) Then
@@ -1248,7 +1335,7 @@ begin
          begin
          begin
            for i:=0 to BHdr.lastlstblock do
            for i:=0 to BHdr.lastlstblock do
              begin
              begin
-               if (index.size-index.position)>=defblocksize then
+               if (index.size-index.position)>=defblocksize then // skips last incomplete block?
                  begin
                  begin
                    Index.read(block,defblocksize);
                    Index.read(block,defblocksize);
                    parselistingblock(@block)
                    parselistingblock(@block)
@@ -1264,6 +1351,7 @@ begin
       Result:=AbortAndTryTextual;
       Result:=AbortAndTryTextual;
     end
     end
   else Index.Free;
   else Index.Free;
+  lookup.free;
 end;
 end;
 
 
 function TChmReader.GetTOCSitemap(ForceXML:boolean=false): TChmSiteMap;
 function TChmReader.GetTOCSitemap(ForceXML:boolean=false): TChmSiteMap;
@@ -1273,19 +1361,19 @@ function TChmReader.GetTOCSitemap(ForceXML:boolean=false): TChmSiteMap;
       Item: TChmSiteMapItem;
       Item: TChmSiteMapItem;
       NextEntry: DWord;
       NextEntry: DWord;
       TopicsIndex: DWord;
       TopicsIndex: DWord;
-      Title: String;
+      Title, Local : String;
     begin
     begin
       Toc.Position:= AItemOffset + 4;
       Toc.Position:= AItemOffset + 4;
       Item := SiteMapITems.NewItem;
       Item := SiteMapITems.NewItem;
       Props := LEtoN(TOC.ReadDWord);
       Props := LEtoN(TOC.ReadDWord);
       if (Props and TOC_ENTRY_HAS_LOCAL) = 0 then
       if (Props and TOC_ENTRY_HAS_LOCAL) = 0 then
-        Item.Text:= ReadStringsEntry(LEtoN(TOC.ReadDWord))
+        Item.AddName(ReadStringsEntry(LEtoN(TOC.ReadDWord)))
       else
       else
       begin
       begin
         TopicsIndex := LEtoN(TOC.ReadDWord);
         TopicsIndex := LEtoN(TOC.ReadDWord);
-        Item.Local := LookupTopicByID(TopicsIndex, Title);
-        Item.Text := Title;
-
+        Local:=LookupTopicByID(TopicsIndex, Title);
+        Item.AddName(Title);
+        Item.AddLocal(Local);
       end;
       end;
       TOC.ReadDWord;
       TOC.ReadDWord;
       Result := LEtoN(TOC.ReadDWord);
       Result := LEtoN(TOC.ReadDWord);
@@ -1724,7 +1812,7 @@ var
   X: Integer;
   X: Integer;
 begin
 begin
   fOnOpenNewFile := AValue;
   fOnOpenNewFile := AValue;
-  if AValue = nil then exit;
+  if not assigned(AValue)  then exit;
   for X := 0 to fUnNotifiedFiles.Count-1 do
   for X := 0 to fUnNotifiedFiles.Count-1 do
     AValue(Self, X);
     AValue(Self, X);
   fUnNotifiedFiles.Clear;
   fUnNotifiedFiles.Clear;

+ 406 - 149
packages/chm/src/chmsitemap.pas

@@ -20,54 +20,105 @@
 }
 }
 unit chmsitemap;
 unit chmsitemap;
 
 
-{$mode objfpc}{$H+}
-
+{$mode Delphi}{$H+}
+{define preferlower}
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, fasthtmlparser;
+  Classes, SysUtils, fasthtmlparser, contnrs, strutils, generics.collections;
 
 
 type
 type
   TChmSiteMapItems = class; // forward
   TChmSiteMapItems = class; // forward
   TChmSiteMap = class;
   TChmSiteMap = class;
+  TChmSiteMapItem = class;
 
 
   { TChmSiteMapItem }
   { TChmSiteMapItem }
 
 
+  TChmSiteMapItemAttrName = (siteattr_NONE,
+                             siteattr_KEYWORD, // alias for name in sitemap
+                             siteattr_NAME,
+                             siteattr_LOCAL,
+                             siteattr_URL,
+                             siteattr_TYPE,
+                             siteattr_SEEALSO,
+                             siteattr_IMAGENUMBER,
+                             siteattr_NEW,
+                             siteattr_COMMENT,
+                             siteattr_MERGE,
+                             siteattr_FRAMENAME,
+                             siteattr_WINDOWNAME,
+                             siteattr_WINDOW_STYLES,
+                             siteattr_EXWINDOW_STYLES,
+                             siteattr_FONT,
+                             siteattr_IMAGELIST,
+                             siteattr_IMAGETYPE
+                            );
+
+  { TChmSiteMapSubItem }
+  TChmSiteMapGenerationOptions = (Default,emitkeyword);
+  TChmSiteMapSubItem = class(TPersistent)
+  private
+    FName,
+    FType,
+    FLocal,
+    FUrl,
+    FSeeAlso  : String;
+    FOwner : TChmSiteMapItem;
+  public
+    constructor Create(AOwner: TChmSiteMapItem);
+    destructor Destroy; override;
+  published
+    property Name : String read FName  write FName;  //hhk
+    property ItemType : String read FType write FType; //both
+    property Local: String read FLocal write FLocal; //both
+    property URL  : String read FURL write FURL;     //both
+    property SeeAlso: String read FSeeAlso write FSeeAlso; //hhk
+  end;
+
+// hhk items:  Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
+// hhc items:  Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
   TChmSiteMapItem = class(TPersistent)
   TChmSiteMapItem = class(TPersistent)
   private
   private
     FChildren: TChmSiteMapItems;
     FChildren: TChmSiteMapItems;
     FComment: String;
     FComment: String;
     FImageNumber: Integer;
     FImageNumber: Integer;
     FIncreaseImageIndex: Boolean;
     FIncreaseImageIndex: Boolean;
-    FKeyWord: String;
-    FLocal: String;
     FOwner: TChmSiteMapItems;
     FOwner: TChmSiteMapItems;
-    FSeeAlso: String;
-    FText: String;
-    FURL: String;
+    FName   : String;
     FMerge : String;
     FMerge : String;
     FFrameName : String;
     FFrameName : String;
     FWindowName : String;
     FWindowName : String;
+    FSubItems : TObjectList;
+    function getlocal: string;
+    function getseealso:string;
+    function getsubitem( index : integer): TChmSiteMapSubItem;
+    function getsubitemcount: integer;
     procedure SetChildren(const AValue: TChmSiteMapItems);
     procedure SetChildren(const AValue: TChmSiteMapItems);
   public
   public
     constructor Create(AOwner: TChmSiteMapItems);
     constructor Create(AOwner: TChmSiteMapItems);
     destructor Destroy; override;
     destructor Destroy; override;
+    procedure AddName(const Name:string);
+    procedure AddLocal(const Local:string);
+    procedure AddSeeAlso(const SeeAlso:string);
+    procedure AddURL(const URL:string);
+    procedure AddType(const AType:string);
+    procedure Sort(Compare: TListSortCompare);
   published
   published
     property Children: TChmSiteMapItems read FChildren write SetChildren;
     property Children: TChmSiteMapItems read FChildren write SetChildren;
-    property Text: String read FText write FText; // Name for TOC; KeyWord for index
-    property KeyWord: String read FKeyWord write FKeyWord;
-    property Local: String read FLocal write FLocal;
-    property URL: String read FURL write FURL;
-    property SeeAlso: String read FSeeAlso write FSeeAlso;
+    property Name: String read FName write FName;
     property ImageNumber: Integer read FImageNumber write FImageNumber default -1;
     property ImageNumber: Integer read FImageNumber write FImageNumber default -1;
     property IncreaseImageIndex: Boolean read FIncreaseImageIndex write FIncreaseImageIndex;
     property IncreaseImageIndex: Boolean read FIncreaseImageIndex write FIncreaseImageIndex;
     property Comment: String read FComment write FComment;
     property Comment: String read FComment write FComment;
     property Owner: TChmSiteMapItems read FOwner;
     property Owner: TChmSiteMapItems read FOwner;
-
+    property Keyword : string read fname; // deprecated;             // Use name, sitemaps don't store the difference.
+    property Local : string read getlocal; // deprecated;            // should work on ALL pairs
+    property Text : string read fname write fname; // deprecated;    // should work on ALL pairs
+    property SeeAlso : string read getseealso; // deprecated;        // should work on ALL pairs
     property FrameName: String read FFrameName write FFrameName;
     property FrameName: String read FFrameName write FFrameName;
     property WindowName: String read FWindowName write FWindowName;
     property WindowName: String read FWindowName write FWindowName;
-//    property Type_: Integer read FType_ write FType_; either Local or URL
     property Merge: String read FMerge write FMerge;
     property Merge: String read FMerge write FMerge;
+    property SubItem[ index :integer]:TChmSiteMapSubItem read getsubitem;
+    property SubItemcount  :integer read getsubitemcount;
   end;
   end;
 
 
   { TChmSiteMapItems }
   { TChmSiteMapItems }
@@ -80,6 +131,7 @@ type
     FParentItem: TChmSiteMapItem;
     FParentItem: TChmSiteMapItem;
     function GetCount: Integer;
     function GetCount: Integer;
     function GetItem(AIndex: Integer): TChmSiteMapItem;
     function GetItem(AIndex: Integer): TChmSiteMapItem;
+    function getparentname: String;
     procedure SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
     procedure SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
   public
   public
     constructor Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
     constructor Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
@@ -95,6 +147,7 @@ type
     property ParentItem: TChmSiteMapItem read FParentItem;
     property ParentItem: TChmSiteMapItem read FParentItem;
     property Owner: TChmSiteMap read FOwner;
     property Owner: TChmSiteMap read FOwner;
     property InternalData: Dword read FInternalData write FInternalData;
     property InternalData: Dword read FInternalData write FInternalData;
+    property ParentName : String read getparentname;
   end;
   end;
   
   
 
 
@@ -130,13 +183,17 @@ type
     FLevel: Integer;
     FLevel: Integer;
     FLevelForced: Boolean;
     FLevelForced: Boolean;
     FWindowStyles: LongInt;
     FWindowStyles: LongInt;
+    FLoadDict : TDictionary<String,TChmSiteMapItemAttrName>;
+    fChmSiteMapGenerationOptions:TChmSiteMapGenerationOptions;
     procedure SetItems(const AValue: TChmSiteMapItems);
     procedure SetItems(const AValue: TChmSiteMapItems);
+    procedure CheckLookup;
   protected
   protected
     procedure FoundTag (ACaseInsensitiveTag, AActualTag: string);
     procedure FoundTag (ACaseInsensitiveTag, AActualTag: string);
     procedure FoundText(AText: string);
     procedure FoundText(AText: string);
   public
   public
     constructor Create(AType: TSiteMapType);
     constructor Create(AType: TSiteMapType);
     destructor Destroy; override;
     destructor Destroy; override;
+    Procedure Sort(Compare: TListSortCompare);
     procedure LoadFromFile(AFileName: String);
     procedure LoadFromFile(AFileName: String);
     procedure LoadFromStream(AStream: TStream);
     procedure LoadFromStream(AStream: TStream);
     procedure SaveToFile(AFileName:String);
     procedure SaveToFile(AFileName:String);
@@ -155,11 +212,50 @@ type
     property UseFolderImages: Boolean read FUseFolderImages write FUseFolderImages;
     property UseFolderImages: Boolean read FUseFolderImages write FUseFolderImages;
     property Font: String read FFont write FFont;
     property Font: String read FFont write FFont;
     property AutoGenerated: Boolean read FAutoGenerated write FAutoGenerated;
     property AutoGenerated: Boolean read FAutoGenerated write FAutoGenerated;
+    property ChmSiteMapGenerationOptions : TChmSiteMapGenerationOptions read fChmSiteMapGenerationOptions write fChmSiteMapGenerationOptions;
   end;
   end;
 
 
+
+function indexitemcompare(Item1, Item2: Pointer): Integer;
 implementation
 implementation
 uses HTMLUtil;
 uses HTMLUtil;
 
 
+const sitemapkws : array[TChmSiteMapItemAttrName] of string = (
+                    '',
+                    'KEYWORD',
+                    'NAME',
+                    'LOCAL',
+                    'URL',
+                    'TYPE',
+                    'SEE ALSO',
+                    'IMAGENUMBER',
+                    'NEW',
+                    'COMMENT',
+                    'MERGE',
+                    'FRAMENAME',
+                    'WINDOWNAME',
+                    'WINDOW STYLES',
+                    'EXWINDOW STYLES',
+                    'FONT',
+                    'IMAGELIST',
+                    'IMAGETYPE');
+
+function indexitemcompare(Item1, Item2: Pointer): Integer;
+begin
+    Result := naturalComparetext(LowerCase(TChmSiteMapItem(item1).name), Lowercase(TChmSiteMapItem(item2).name));
+end;
+{ TChmSiteMapSubItem }
+
+constructor TChmSiteMapSubItem.Create(AOwner: TChmSiteMapItem);
+begin
+  FOwner:=AOwner;
+end;
+
+destructor TChmSiteMapSubItem.Destroy;
+begin
+  inherited Destroy;
+end;
+
 { TChmSiteMapTree }
 { TChmSiteMapTree }
 
 
 procedure TChmSiteMap.SetItems(const AValue: TChmSiteMapItems);
 procedure TChmSiteMap.SetItems(const AValue: TChmSiteMapItems);
@@ -168,6 +264,16 @@ begin
   FItems:=AValue;
   FItems:=AValue;
 end;
 end;
 
 
+procedure TChmSiteMap.CheckLookup;
+var en : TChmSiteMapItemAttrName;
+begin
+  if assigned(FLoadDict) then
+    exit;
+  FLoadDict :=TDictionary<String,TChmSiteMapItemAttrName>.Create;
+  for en:=succ(low(en)) to high(en) do
+    FLoadDict.add(sitemapkws[en],en);
+end;
+
 procedure TChmSiteMap.FoundTag(ACaseInsensitiveTag, AActualTag: string);
 procedure TChmSiteMap.FoundTag(ACaseInsensitiveTag, AActualTag: string);
     procedure NewSiteMapItem;
     procedure NewSiteMapItem;
     begin
     begin
@@ -196,131 +302,98 @@ procedure TChmSiteMap.FoundTag(ACaseInsensitiveTag, AActualTag: string);
       else FCurrentItems := nil;
       else FCurrentItems := nil;
       Dec(FLevel);
       Dec(FLevel);
     end;
     end;
+
+// hhk items:  Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
+// hhc items:  Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
 var
 var
   TagName,
   TagName,
-  //TagAttribute,
   TagAttributeName,
   TagAttributeName,
   TagAttributeValue: String;
   TagAttributeValue: String;
   isParam,IsMerged : string;
   isParam,IsMerged : string;
+  TagAttrName  : TChmSiteMapItemAttrName;
 begin
 begin
-  //WriteLn('TAG:', AActualTag);
   TagName := GetTagName(ACaseInsensitiveTag);
   TagName := GetTagName(ACaseInsensitiveTag);
-
-{  if not (smtHTML in FSiteMapTags) then begin
-    if (TagName = 'HTML') or (TagName = '/HTML') then Include(FSiteMapTags, smtHTML);
-  end
-  else begin // looking for /HTML
-    if TagName = '/HTML' then Exclude(FSiteMapTags, smtHTML);
-  end;}
-
-  //if (smtHTML in FSiteMapTags) then begin
-     if not (smtBODY in FSiteMapTags) then begin
-       if TagName = 'BODY' then Include(FSiteMapTags, smtBODY);
-     end
-     else begin
-       if TagName = '/BODY' then Exclude(FSiteMapTags, smtBODY);
+   if TagName = 'UL' then begin
+     IncreaseULevel;
+   end
+   else if TagName = '/UL' then begin
+     DecreaseULevel;
+   end
+   else if (TagName = 'LI') and (FLevel = 0) then
+     FLevelForced := True
+   else if TagName = 'OBJECT' then begin
+     Include(FSiteMapBodyTags, smbtOBJECT);
+     if FLevelForced then
+       IncreaseULevel;
+     If FLevel > 0 then // if it is zero it is the site properties
+       NewSiteMapItem;
+   end
+   else if TagName = '/OBJECT' then begin
+     Exclude(FSiteMapBodyTags, smbtOBJECT);
+     if FLevelForced then
+     begin
+       DecreaseULevel;
+       FLevelForced := False;
      end;
      end;
-
-     if (smtBODY in FSiteMapTags) then begin
-       //WriteLn('GOT TAG: ', AActualTag);
-       if TagName = 'UL' then begin
-         //WriteLN('Inc Level');
-         IncreaseULevel;
-       end
-       else if TagName = '/UL' then begin
-         //WriteLN('Dec Level');
-         DecreaseULevel;
-       end
-       else if (TagName = 'LI') and (FLevel = 0) then
-         FLevelForced := True
-       else if TagName = 'OBJECT' then begin
-         Include(FSiteMapBodyTags, smbtOBJECT);
-         if FLevelForced then
-           IncreaseULevel;
-         If FLevel > 0 then // if it is zero it is the site properties
-           NewSiteMapItem;
-       end
-       else if TagName = '/OBJECT' then begin
-         Exclude(FSiteMapBodyTags, smbtOBJECT);
-         if FLevelForced then
+   end
+   else begin // we are the properties of the object tag
+     if (smbtOBJECT in FSiteMapBodyTags) then
+       begin
+        if (FLevel > 0 ) then
          begin
          begin
-           DecreaseULevel;
-           FLevelForced := False;
-         end;
-       end
-       else begin // we are the properties of the object tag
-         if (smbtOBJECT in FSiteMapBodyTags) then
-           begin
-            if (FLevel > 0 ) then 
-             begin
-                if LowerCase(GetTagName(AActualTag)) = 'param' then begin
-                  TagAttributeName := GetVal(AActualTag, 'name');
-                TagAttributeValue := GetVal(AActualTag, 'value');
-                //writeln('name,value',tagattributename, ' ',tagattributevalue);
-                if TagAttributeName <> '' then begin
-                  if CompareText(TagAttributeName, 'keyword') = 0 then begin
-                    ActiveItem.Text := TagAttributeValue;
-                  end
-                  else if CompareText(TagAttributeName, 'name') = 0 then begin
-                    if ActiveItem.Text = '' then ActiveItem.Text := TagAttributeValue;
-                  end
-                  else if CompareText(TagAttributeName, 'local') = 0 then begin
-                    ActiveItem.Local := TagAttributeValue;
-                  end
-                  else if CompareText(TagAttributeName, 'URL') = 0 then begin
-                    ActiveItem.URL := TagAttributeValue;
-                  end
-                  else if CompareText(TagAttributeName, 'ImageNumber') = 0 then begin
-                    ActiveItem.ImageNumber := StrToInt(TagAttributeValue);
-                  end
-                  else if CompareText(TagAttributeName, 'New') = 0 then begin
-                    ActiveItem.IncreaseImageIndex := (LowerCase(TagAttributeValue) = 'yes');
-                  end
-                  else if CompareText(TagAttributeName, 'Comment') = 0 then begin
-                    ActiveItem.Comment := TagAttributeValue
-                  end
-                  else if CompareText(TagAttributeName, 'Merge') = 0 then begin
-                    ActiveItem.Merge:= TagAttributeValue
-                  end;
-                  //else if CompareText(TagAttributeName, '') = 0 then begin
-                  //end;
-                end;
-              end;
-            end
-           else
-             begin // object and level is zero?
-               if LowerCase(GetTagName(AActualTag)) = 'param' then begin
-                 begin
-                   TagAttributeName := uppercase(GetVal(AActualTag, 'name'));
-                   TagAttributeValue := GetVal(AActualTag, 'value');
-                   if TagAttributeName = 'FRAMENAME' then
-                     framename:=TagAttributeValue
-                   else
-                     if TagAttributeName = 'WINDOWNAME' then
-                       WINDOWname:=TagAttributeValue
-                   else
-                     if TagAttributeName = 'WINDOW STYLES' then
-                       WindowStyles:=StrToIntDef(TagAttributeValue,0)
-                   else
-                     if TagAttributeName = 'EXWINDOW STYLES' then
-                       ExWindowStyles:=StrToIntDef(TagAttributeValue,0)
-                   else
-                     if TagAttributeName = 'FONT' then
-                       FONT:=TagAttributeValue
-                   else
-                     if TagAttributeName = 'IMAGELIST' then
-                      IMAGELIST:=TagAttributeValue
-                    else
-                     if TagAttributeName = 'IMAGETYPE' then
-                      UseFolderImages:=uppercase(TagAttributeValue)='FOLDER';
-                  // writeln('0:',flevel,' ' ,aactualtag,' ',tagname,' ' ,tagattributename, ' ' ,tagattributevalue);
-                 end;
+            if LowerCase(GetTagName(AActualTag)) = 'param' then begin
+              TagAttributeName := GetVal(AActualTag, 'name');
+              TagAttributeValue := GetVal(AActualTag, 'value');
+
+              // a hash reduces comparisons and casing, and generics make it easy.
+              if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
+                 TagAttrName:=siteattr_none;
+
+              if TagAttrName <> siteattr_none then begin
+                 case TagAttrName of
+                 siteattr_KEYWORD,
+                 siteattr_NAME         : Activeitem.AddName(TagAttributeValue);
+                 siteattr_LOCAL        : ActiveItem.AddLocal(TagAttributeValue);
+                 siteattr_URL          : ActiveItem.AddURL (TagAttributeValue);
+                 siteattr_TYPE         : ActiveItem.AddType (TagAttributeValue);
+                 siteattr_SEEALSO      : ActiveItem.AddSeeAlso(TagAttributeValue);
+                 siteattr_IMAGENUMBER  : ActiveItem.ImageNumber := StrToInt(TagAttributeValue);
+                 siteattr_NEW          : ActiveItem.IncreaseImageIndex := (LowerCase(TagAttributeValue) = 'yes');
+                 siteattr_COMMENT      : ActiveItem.Comment := TagAttributeValue;
+                 siteattr_MERGE        : ActiveItem.Merge:= TagAttributeValue;
+                 siteattr_FRAMENAME    : ActiveItem.FrameName:=TagAttributeValue;
+                 siteattr_WINDOWNAME   : ActiveItem.WindowName:=TagAttributeValue;
                  end;
                  end;
+              end;
+            end;
+         end
+       else
+         begin // object and level is zero?
+           if LowerCase(GetTagName(AActualTag)) = 'param' then begin
+             begin
+               TagAttributeName := uppercase(GetVal(AActualTag, 'name'));
+               TagAttributeValue := GetVal(AActualTag, 'value');
+               if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
+                  TagAttrName:=siteattr_none;
+               if TagAttrName <> siteattr_none then begin
+                  case TagAttrName of
+                   siteattr_FRAMENAME       : FrameName:=TagAttributeValue;
+                   siteattr_WINDOWNAME      : WindowName:=TagAttributeValue;
+                   siteattr_WINDOW_STYLES   : WindowStyles:=StrToIntDef(TagAttributeValue,0);
+                   siteattr_EXWINDOW_STYLES : ExWindowStyles:=StrToIntDef(TagAttributeValue,0);
+                   siteattr_FONT            : Font:=TagAttributeValue;
+                   siteattr_IMAGELIST       : ImageList:=TagAttributeValue;
+                   siteattr_IMAGETYPE       : UseFolderImages:=uppercase(TagAttributeValue)='FOLDER';
+                   end;
              end;
              end;
-          end;
-       end;
-     end;
-  //end
+              // writeln('0:',flevel,' ' ,aactualtag,' ',tagname,' ' ,tagattributename, ' ' ,tagattributevalue);
+             end;
+             end;
+         end;
+      end;
+   end;
+// end; {body}
+  //end   {html}
 end;
 end;
 
 
 procedure TChmSiteMap.FoundText(AText: string);
 procedure TChmSiteMap.FoundText(AText: string);
@@ -342,14 +415,22 @@ destructor TChmSiteMap.Destroy;
 begin
 begin
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   FItems.Free;
   FItems.Free;
+  FLoadDict.Free;
+
   Inherited Destroy;
   Inherited Destroy;
 end;
 end;
 
 
+procedure TChmSiteMap.Sort(Compare: TListSortCompare);
+begin
+  FItems.sort(compare);
+end;
+
 procedure TChmSiteMap.LoadFromFile(AFileName: String);
 procedure TChmSiteMap.LoadFromFile(AFileName: String);
 var
 var
   Buffer: String;
   Buffer: String;
   TmpStream: TMemoryStream;
   TmpStream: TMemoryStream;
 begin
 begin
+  CheckLookup;
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   TmpStream := TMemoryStream.Create;
   TmpStream := TMemoryStream.Create;
   try
   try
@@ -362,8 +443,8 @@ begin
   end;
   end;
   FHTMLParser := THTMLParser.Create(Buffer);
   FHTMLParser := THTMLParser.Create(Buffer);
   try
   try
-    FHTMLParser.OnFoundTag := @FoundTag;
-    FHTMLParser.OnFoundText := @FoundText;
+    FHTMLParser.OnFoundTag := FoundTag;
+    FHTMLParser.OnFoundText := FoundText;
     FHTMLParser.Exec;
     FHTMLParser.Exec;
   finally
   finally
     FreeAndNil(FHTMLParser);
     FreeAndNil(FHTMLParser);
@@ -374,12 +455,13 @@ procedure TChmSiteMap.LoadFromStream(AStream: TStream);
 var
 var
   Buffer: String;
   Buffer: String;
 begin
 begin
+  CheckLookup;
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   if Assigned(FHTMLParser) then FHTMLParser.Free;
   SetLength(Buffer, AStream.Size-AStream.Position);
   SetLength(Buffer, AStream.Size-AStream.Position);
   if AStream.Read(Buffer[1], AStream.Size-AStream.Position) > 0 then begin;
   if AStream.Read(Buffer[1], AStream.Size-AStream.Position) > 0 then begin;
     FHTMLParser := THTMLParser.Create(Buffer);
     FHTMLParser := THTMLParser.Create(Buffer);
-    FHTMLParser.OnFoundTag := @FoundTag;
-    FHTMLParser.OnFoundText := @FoundText;
+    FHTMLParser.OnFoundTag := FoundTag;
+    FHTMLParser.OnFoundText := FoundText;
     FHTMLParser.Exec;
     FHTMLParser.Exec;
     FreeAndNil(FHTMLParser);
     FreeAndNil(FHTMLParser);
   end;
   end;
@@ -397,6 +479,9 @@ begin
     end;
     end;
 end;
 end;
 
 
+// hhk items:  Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
+// hhc items:  Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
+
 procedure TChmSiteMap.SaveToStream(AStream: TStream);
 procedure TChmSiteMap.SaveToStream(AStream: TStream);
 var
 var
   Indent: Integer;
   Indent: Integer;
@@ -408,44 +493,86 @@ var
      AStream.Write(AString[1], Length(AString));
      AStream.Write(AString[1], Length(AString));
      AStream.WriteByte(10);
      AStream.WriteByte(10);
   end;
   end;
+  procedure WriteStringNoIndent(AString: String);
+  var
+    I: Integer;
+  begin
+     AStream.Write(AString[1], Length(AString));
+  end;
+
   procedure WriteParam(AName: String; AValue: String);
   procedure WriteParam(AName: String; AValue: String);
   begin
   begin
     WriteString('<param name="'+AName+'" value="'+AValue+'">');
     WriteString('<param name="'+AName+'" value="'+AValue+'">');
   end;
   end;
   procedure WriteEntries(AItems: TChmSiteMapItems);
   procedure WriteEntries(AItems: TChmSiteMapItems);
   var
   var
-    I : Integer;
+    I,J : Integer;
     Item: TChmSiteMapItem;
     Item: TChmSiteMapItem;
+    Sub : TChmSiteMapSubItem;
+    lemitkeyword : boolean;
   begin
   begin
+    lemitkeyword:=ChmSiteMapGenerationOptions=emitkeyword;
     for I := 0 to AItems.Count-1 do begin
     for I := 0 to AItems.Count-1 do begin
       Item := AItems.Item[I];
       Item := AItems.Item[I];
+
+      {$ifdef preferlower}
+      WriteString('<li> <object type="text/sitemap">');
+      {$else}
       WriteString('<LI> <OBJECT type="text/sitemap">');
       WriteString('<LI> <OBJECT type="text/sitemap">');
+      {$endif}
       Inc(Indent, 8);
       Inc(Indent, 8);
 
 
-      if (SiteMapType = stIndex) and ((Item.Children.Count > 0) or (item.seealso<>'')) then
-         WriteParam('Keyword', Item.Text);
-      //if Item.KeyWord <> '' then WriteParam('Keyword', Item.KeyWord);
-      if Item.Text <> '' then WriteParam('Name', Item.Text);
-      if (Item.Local <> '') or (SiteMapType = stIndex) then WriteParam('Local', StringReplace(Item.Local, '\', '/', [rfReplaceAll]));
-      if Item.URL <> '' then WriteParam('URL', StringReplace(Item.URL, '\', '/', [rfReplaceAll]));
-      if (SiteMapType = stIndex) and (Item.SeeAlso <> '') then WriteParam('See Also', Item.SeeAlso);
-      //if Item.FrameName <> '' then WriteParam('FrameName', Item.FrameName);
-      //if Item.WindowName <> '' then WriteParam('WindowName', Item.WindowName);
+      if Item.Name<>'' then
+        begin
+          if lemitkeyword then
+            WriteParam('Keyword', item.Name)
+          else
+            WriteParam('Name', Item.Name);
+        end;
+
+      if item.FSubItems.count>0 then
+        begin
+          For j:=0 to item.FSubItems.count-1 do
+            begin
+              Sub:=TChmSiteMapSubItem(item.fsubitems[j]);
+              if Sub.Name <> ''     then WriteParam('Name', Sub.Name);
+              if Sub.ItemType <> '' then WriteParam('Type', Sub.ItemType);
+              if Sub.Local <> ''    then WriteParam('Local', Sub.Local);
+              if Sub.URL <> ''      then WriteParam('URL', Sub.URL);
+              if Sub.SeeAlso <> ''  then WriteParam('See Also', Sub.SeeAlso);
+            end;
+        end;
+      if Item.FrameName <> '' then WriteParam('FrameName', Item.FrameName);
+      if Item.WindowName <> '' then WriteParam('WindowName', Item.WindowName);
       if Item.Comment <> '' then WriteParam('Comment', Item.Comment);
       if Item.Comment <> '' then WriteParam('Comment', Item.Comment);
-      if (SiteMapType = stTOC) and (Item.IncreaseImageIndex) then WriteParam('New', 'yes'); // is this a correct value?
-      if (SiteMapType = stTOC) and (Item.ImageNumber <> -1) then WriteParam('ImageNumber', IntToStr(Item.ImageNumber));
-
+      if (SiteMapType = stTOC) and (Item.IncreaseImageIndex) then
+          WriteParam('New', 'yes'); // is this a correct value?
+      if (SiteMapType = stTOC) and (Item.ImageNumber <> -1) then
+          WriteParam('ImageNumber', IntToStr(Item.ImageNumber));
       Dec(Indent, 3);
       Dec(Indent, 3);
+      {$ifdef preferlower}
+      WriteString('</object>');
+      {$else}
       WriteString('</OBJECT>');
       WriteString('</OBJECT>');
+      {$endif}
       Dec(Indent, 5);
       Dec(Indent, 5);
 
 
       // Now Sub Entries
       // Now Sub Entries
       if Item.Children.Count > 0 then begin
       if Item.Children.Count > 0 then begin
-        WriteString('<UL>');
+        {$ifdef preferlower}
+        WriteString('<ul>');
+        {$else}
+        WriteString('<UL> ');
+        {$endif}
         Inc(Indent, 8);
         Inc(Indent, 8);
         WriteEntries(Item.Children);
         WriteEntries(Item.Children);
         Dec(Indent, 8);
         Dec(Indent, 8);
-        WriteString('</UL>');
+        {$ifdef preferlower}
+        WriteString('</ul>');
+        {$else}
+        WriteString('</UL>'); //writestringnoident
+        {$endif}
+
       end;
       end;
     end;
     end;
   end;
   end;
@@ -475,7 +602,7 @@ begin
     // both TOC and Index have font
     // both TOC and Index have font
     if Font <> '' then
     if Font <> '' then
       WriteParam('Font', Font);
       WriteParam('Font', Font);
-    Dec(Indent, 8);
+  Dec(Indent, 8);
   WriteString('</OBJECT>');
   WriteString('</OBJECT>');
   
   
   // And now the items
   // And now the items
@@ -501,19 +628,137 @@ begin
   FChildren := AValue;
   FChildren := AValue;
 end;
 end;
 
 
+function TChmSiteMapItem.getlocal: string;
+begin
+  result:='';
+  if FSubItems.count>0 then
+     result:=TChmSiteMapSubItem(FSubItems[0]).local;
+end;
+
+function TChmSiteMapItem.getseealso: string;
+begin
+  result:='';
+  if FSubItems.count>0 then
+    result:=TChmSiteMapSubItem(FSubItems[FSubItems.count-1]).SeeAlso;
+end;
+
+function TChmSiteMapItem.getsubitem( index : integer): TChmSiteMapSubItem;
+begin
+  result:=nil;
+  if index<FSubItems.count then
+    result:=TChmSiteMapSubItem(FSubItems[index]);
+end;
+
+function TChmSiteMapItem.getsubitemcount: integer;
+begin
+   result:=FSubItems.count;
+end;
+
 constructor TChmSiteMapItem.Create(AOwner: TChmSiteMapItems);
 constructor TChmSiteMapItem.Create(AOwner: TChmSiteMapItems);
 begin
 begin
   Inherited Create;
   Inherited Create;
   FOwner := AOwner;
   FOwner := AOwner;
   FChildren := TChmSiteMapItems.Create(Owner.Owner, Self);
   FChildren := TChmSiteMapItems.Create(Owner.Owner, Self);
+  FSubItems := TObjectList.Create(true);
+  imagenumber:=-1;
 end;
 end;
 
 
 destructor TChmSiteMapItem.Destroy;
 destructor TChmSiteMapItem.Destroy;
 begin
 begin
+  fsubitems.Free;
   FChildren.Free;
   FChildren.Free;
   Inherited Destroy;
   Inherited Destroy;
 end;
 end;
 
 
+procedure TChmSiteMapItem.AddName(const Name: string);
+var sub :TChmSiteMapSubItem;
+begin
+  if fname='' then
+    fname:=name
+  else
+    begin
+      sub :=TChmSiteMapSubItem.create(self);
+      FSubItems.add(sub);
+      sub.Name:=Name;
+    end;
+end;
+
+procedure TChmSiteMapItem.AddLocal(const Local: string);
+var sub :TChmSiteMapSubItem;
+    addnew : boolean;
+begin
+   if fsubitems.count>0 then
+      begin
+        sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
+        if sub.FLocal<>'' then
+          begin
+            sub.flocal:=local;
+            exit;
+          end;
+      end;
+   sub :=TChmSiteMapSubItem.create(self);
+   FSubItems.add(sub);
+//   sub.name:=name;
+   sub.Local:=Local;
+end;
+
+procedure TChmSiteMapItem.AddSeeAlso(const SeeAlso: string);
+// see also is mutually exclusive with "local url", so addition procedure is same as "local"
+var sub :TChmSiteMapSubItem;
+begin
+   if fsubitems.count>0 then
+      begin
+        sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
+        if sub.FSeeAlso<>'' then
+          begin
+            sub.FSeeAlso:=SeeAlso;
+            exit;
+          end;
+      end;
+   sub :=TChmSiteMapSubItem.create(self);
+   FSubItems.add(sub);
+   sub.FSeeAlso:=SeeAlso;
+end;
+
+
+procedure TChmSiteMapItem.AddURL(const URL: string);
+var sub :TChmSiteMapSubItem;
+begin
+   if fsubitems.count>0 then
+      begin
+        sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
+        if sub.FURL<>'' then
+          begin
+            sub.fURL:=URL;
+            exit;
+          end;
+      end
+   { else not possible according to chmspec. An URL must always follow a "local" item}
+end;
+
+procedure TChmSiteMapItem.AddType(const AType: string);
+// in Tocs, Type can be the first is the same as local
+var sub :TChmSiteMapSubItem;
+begin
+   if fsubitems.count>0 then
+      begin
+        sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
+        if sub.ItemType<>'' then
+          begin
+            sub.ItemType:=AType;
+            exit;
+          end;
+      end;
+   sub :=TChmSiteMapSubItem.create(self);
+   FSubItems.add(sub);
+   sub.ItemType:=AType;
+end;
+
+procedure TChmSiteMapItem.Sort(Compare: TListSortCompare);
+begin
+  FChildren.sort(compare);
+end;
+
 { TChmSiteMapItems }
 { TChmSiteMapItems }
 
 
 function TChmSiteMapItems.GetItem(AIndex: Integer): TChmSiteMapItem;
 function TChmSiteMapItems.GetItem(AIndex: Integer): TChmSiteMapItem;
@@ -521,6 +766,15 @@ begin
   Result := TChmSiteMapItem(FList.Items[AIndex]);
   Result := TChmSiteMapItem(FList.Items[AIndex]);
 end;
 end;
 
 
+function TChmSiteMapItems.getparentname: String;
+begin
+  result:='Not assigned';
+  if assigned(fparentitem) then
+    begin
+      result:=FParentItem.name;
+    end;
+end;
+
 function TChmSiteMapItems.GetCount: Integer;
 function TChmSiteMapItems.GetCount: Integer;
 begin
 begin
   Result := FList.Count;
   Result := FList.Count;
@@ -577,8 +831,11 @@ begin
 end;
 end;
 
 
 procedure TChmSiteMapItems.Sort(Compare: TListSortCompare);
 procedure TChmSiteMapItems.Sort(Compare: TListSortCompare);
+var I :Integer;
 begin
 begin
   FList.Sort(Compare);
   FList.Sort(Compare);
+  for i:=0 to flist.Count-1 do
+    TChmSiteMapItem(flist[i]).sort(Compare)
 end;
 end;
 
 
 end.
 end.

+ 34 - 0
packages/chm/src/chmtypes.pas

@@ -136,6 +136,7 @@ type
                                             // of certain fields. Needs to be inserted into #windows stream
                                             // of certain fields. Needs to be inserted into #windows stream
                 Constructor create(s:string='');
                 Constructor create(s:string='');
                 procedure load_from_ini(txt:string);
                 procedure load_from_ini(txt:string);
+                procedure SaveToIni(out s: string);
                 procedure savetoxml(cfg:TXMLConfig;key:string);
                 procedure savetoxml(cfg:TXMLConfig;key:string);
                 procedure loadfromxml(cfg:TXMLConfig;key:string);
                 procedure loadfromxml(cfg:TXMLConfig;key:string);
                 procedure assign(obj : TCHMWindow);
                 procedure assign(obj : TCHMWindow);
@@ -547,6 +548,39 @@ begin
   wm_notify_id             :=getnextint(txt,ind,len,flags,valid_unknown1);
   wm_notify_id             :=getnextint(txt,ind,len,flags,valid_unknown1);
 end;
 end;
 
 
+
+procedure TCHMWindow.SaveToIni(out s: string);
+begin
+  s := window_type + '=';
+  s := s + '"' + Title_bar_text + '"';
+  s := s + ',"' + Toc_file + '"';
+  s := s + ',"' + index_file + '"';
+  s := s + ',"' + Default_File + '"';
+  s := s + ',"' + Home_button_file + '"';
+  s := s + ',"' + Jumpbutton_1_File + '"';
+  s := s + ',"' + Jumpbutton_1_Text + '"';
+  s := s + ',"' + Jumpbutton_2_File + '"';
+  s := s + ',"' + Jumpbutton_2_Text + '"';
+  s := s + ',0x' + IntToHex(nav_style, 1);
+  s := s + ',' + IntToStr(navpanewidth);
+  s := s + ',0x' + IntToHex(buttons, 1);
+  s := s + ',[' + IntToStr(left);
+  s := s + ',' + IntToStr(top);
+  s := s + ',' + IntToStr(right);
+  s := s + ',' + IntToStr(bottom) + ']';
+  s := s + ',0x' + IntToHex(styleflags, 1);
+  if xtdstyleflags <> 0 then
+   s := s + ',0x' + IntToHex(xtdstyleflags, 1)
+  else
+   s := s + ',';
+  s := s + ',0x' + IntToHex(window_show_state, 1);
+  s := s + ',' + IntToStr(navpane_initially_closed);
+  s := s + ',' + IntToStr(navpane_default);
+  s := s + ',' + IntToStr(navpane_location);
+  //s := s + ',' + IntToStr(wm_notify_id);
+end;
+
+
 procedure TCHMWindow.savetoxml(cfg:TXMLConfig;key:string);
 procedure TCHMWindow.savetoxml(cfg:TXMLConfig;key:string);
 begin
 begin
   cfg.setvalue(key+'window_type',window_type);
   cfg.setvalue(key+'window_type',window_type);

+ 105 - 36
packages/chm/src/chmwriter.pas

@@ -6,7 +6,7 @@
   option) any later version.
   option) any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
   for more details.
   for more details.
 
 
@@ -22,7 +22,7 @@ unit chmwriter;
 {$MODE OBJFPC}{$H+}
 {$MODE OBJFPC}{$H+}
 
 
 interface
 interface
-uses Classes, ChmBase, chmtypes, chmspecialfiles, HtmlIndexer, chmsitemap, contnrs, StreamEx, Avl_Tree, lzxcompressthread;
+uses Generics.Collections,Classes, ChmBase, chmtypes, chmspecialfiles, HtmlIndexer, chmsitemap, contnrs, StreamEx, Avl_Tree, lzxcompressthread;
 
 
 Const
 Const
    DefaultHHC = 'Default.hhc';
    DefaultHHC = 'Default.hhc';
@@ -126,7 +126,8 @@ Type
     property TempRawStream: TStream read FTempStream write SetTempRawStream;
     property TempRawStream: TStream read FTempStream write SetTempRawStream;
     property ReadmeMessage : String read fReadmeMessage write fReadmeMessage;
     property ReadmeMessage : String read fReadmeMessage write fReadmeMessage;
     property Cores : integer read fcores write fcores;
     property Cores : integer read fcores write fcores;
-    //property LocaleID: dword read ITSFHeader.LanguageID write ITSFHeader.LanguageID;
+    { MS Locale ID code }
+    property LocaleID: dword read ITSFHeader.LanguageID write ITSFHeader.LanguageID;
   end;
   end;
 
 
   { TChmWriter }
   { TChmWriter }
@@ -154,6 +155,7 @@ Type
     FAvlStrings   : TAVLTree;    // dedupe strings
     FAvlStrings   : TAVLTree;    // dedupe strings
     FAVLTopicdedupe : TAVlTree;  // Topic deduping, if we load it both from hhp and TOC
     FAVLTopicdedupe : TAVlTree;  // Topic deduping, if we load it both from hhp and TOC
     FAvlURLStr    : TAVLTree;    // dedupe urltbl + binindex must resolve URL to topicid
     FAvlURLStr    : TAVLTree;    // dedupe urltbl + binindex must resolve URL to topicid
+    FDictTopicsUrlInd    : specialize TDictionary<string,integer>; // if url exists reuse topic.
     SpareString   : TStringIndex;
     SpareString   : TStringIndex;
     SpareUrlStr   : TUrlStrIndex;
     SpareUrlStr   : TUrlStrIndex;
     FWindows      : TObjectList;
     FWindows      : TObjectList;
@@ -186,6 +188,7 @@ Type
     function AddURL(AURL: String; TopicsIndex: DWord): LongWord;
     function AddURL(AURL: String; TopicsIndex: DWord): LongWord;
     procedure CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec);
     procedure CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec);
     function AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer;
     function AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer;
+    function AddTopicindex(ATitle,AnUrl:AnsiString;code:integer=-1):integer;
     procedure ScanSitemap(asitemap:TCHMSiteMap);
     procedure ScanSitemap(asitemap:TCHMSiteMap);
     function NextTopicIndex: Integer;
     function NextTopicIndex: Integer;
     procedure Setwindows (AWindowList:TObjectList);
     procedure Setwindows (AWindowList:TObjectList);
@@ -1521,6 +1524,7 @@ begin
   FDefaultWindow:= '';
   FDefaultWindow:= '';
   FMergeFiles   :=TStringList.Create;
   FMergeFiles   :=TStringList.Create;
   FNrTopics     :=0;
   FNrTopics     :=0;
+  FDictTopicsUrlInd    :=specialize TDictionary<string,integer>.Create;
 end;
 end;
 
 
 destructor TChmWriter.Destroy;
 destructor TChmWriter.Destroy;
@@ -1543,7 +1547,7 @@ begin
   FAVLTopicdedupe.FreeAndClear;
   FAVLTopicdedupe.FreeAndClear;
   FAVLTopicdedupe.free;
   FAVLTopicdedupe.free;
   FWindows.Free;
   FWindows.Free;
-
+  FDictTopicsUrlInd.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
@@ -1664,6 +1668,7 @@ var
     TopicEntry: TTopicEntry;
     TopicEntry: TTopicEntry;
 
 
 begin
 begin
+    ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]);
     anurl:=StringReplace(anurl, '\', '/', [rfReplaceAll]);
     anurl:=StringReplace(anurl, '\', '/', [rfReplaceAll]);
     if ATitle <> '' then
     if ATitle <> '' then
       TopicEntry.StringsOffset := AddString(ATitle)
       TopicEntry.StringsOffset := AddString(ATitle)
@@ -1691,6 +1696,35 @@ begin
     FTopicsStream.WriteDWord(LEtoN(TopicEntry.URLTableOffset));
     FTopicsStream.WriteDWord(LEtoN(TopicEntry.URLTableOffset));
     FTopicsStream.WriteWord(LEtoN(TopicEntry.InContents));
     FTopicsStream.WriteWord(LEtoN(TopicEntry.InContents));
     FTopicsStream.WriteWord(LEtoN(TopicEntry.Unknown));
     FTopicsStream.WriteWord(LEtoN(TopicEntry.Unknown));
+    {$ifdef binindex}
+    writeln('topout:',result, ' ' , TopicEntry.StringsOffset,' ' ,TopicEntry.URLTableOffset, ' ',atitle,' - ', anurl);
+    {$endif}
+end;
+
+function TChmWriter.AddTopicindex(ATitle, AnUrl: AnsiString; code: integer
+  ): integer;
+
+begin
+   ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]);
+
+  // adhoc subsitutions. Replace with real code if exact behaviour is known.
+{  Atitle:=StringReplace(atitle, '&x27;', '''', [rfReplaceAll]);
+  if length(atitle)>0 then
+    atitle[1]:=uppercase(atitle[1])[1];}
+  {$ifdef binindex}
+  writeln('Enter ',ATitle,' ',AnUrl);
+  {$endif}
+  if FDictTopicsUrlInd.trygetvalue(anurl,result) then
+   begin
+     {$ifdef binindex}
+       writeln('found:',result);
+     {$endif}
+   end
+   else
+    begin
+      result:=addtopic(atitle,anurl);
+      FDictTopicsUrlInd.add(anurl,result);
+    end;
 end;
 end;
 
 
 procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap);
 procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap);
@@ -2039,32 +2073,64 @@ begin
   inc(blockind,indexentrysize);
   inc(blockind,indexentrysize);
 end;
 end;
 
 
-procedure CreateEntry(Item:TChmSiteMapItem;Str:WideString;commaatposition:integer);
+procedure WritestrNT(var p:pbyte;const str:Unicodestring);
+var i : integer;
+    p2 : pbyte;
+begin
+  p2:=p;
+  for i:=1 to Length(str) do
+    WriteWord(p2,Word(str[i]));   // write the wstr in little endian
+  WriteWord(p2,0);                // NT
+  p:=p2;
+end;
+
+procedure CreateEntry(Item:TChmSiteMapItem;const Str:UnicodeString;commaatposition,level:integer);
 
 
 var p      : pbyte;
 var p      : pbyte;
     topicid: integer;
     topicid: integer;
     seealso: Integer;
     seealso: Integer;
     entrysize:Integer;
     entrysize:Integer;
     i      : Integer;
     i      : Integer;
+    sb :TChmSiteMapSubItem;
 begin
 begin
   inc(TotalEntries);
   inc(TotalEntries);
   fillchar(testblock[0],DefBlockSize,#0);
   fillchar(testblock[0],DefBlockSize,#0);
   p:=@TestBlock[0];
   p:=@TestBlock[0];
-  for i:=1 to Length(str) do
-    WriteWord(p,Word(str[i]));   // write the wstr in little endian
-  WriteWord(p,0);                // NT
-//  if item.seealso='' then    // no seealso for now
-    seealso:=0;
- // else
-//    seealso:=2;
+
+  WritestrNT(p,Str);
+  if item.seealso='' then    // no seealso for now
+    seealso:=0
+   else
+    seealso:=2;
   WriteWord(p,seealso);          // =0 not a see also 2 =seealso
   WriteWord(p,seealso);          // =0 not a see also 2 =seealso
-  WriteWord(p,0);                // Entrydepth.  We can't know it, so write 2.
+  WriteWord(p,level);            // Entrydepth.  We can't know it, so write 2.
   WriteDword(p,commaatposition); // position of the comma
   WriteDword(p,commaatposition); // position of the comma
   WriteDword(p,0);               // unused 0
   WriteDword(p,0);               // unused 0
-  WriteDword(p,1);               // for now only local pair.
-  TopicId:=AddTopic(Item.Text,item.Local);
-  WriteDword(p,TopicId);
-  // if seealso then _here_ a wchar NT string with seealso?
+
+  if seealso=2 then
+   begin
+     {$ifdef binindex}
+     write('!seealso');
+     {$endif}
+     WriteDword(p,1);
+     WritestrNT(p,item.seealso)
+   end
+  else
+    begin
+      WriteDword(p,item.SubItemcount);
+      for i:=0 to item.SubItemcount-1 do
+        begin
+          sb:=item.SubItem[i];
+          if sb.name='' then
+            sb.name:=item.name;
+          {$ifdef binindex}
+          writeln('---',sb.name,' ',sb.local);
+          {$endif}
+          TopicId:=AddTopicIndex(sb.Name,sb.Local);
+          WriteDword(p,TopicId);
+        end;
+    end;
+
   WriteDword(p,1);               // always 1 (unknown);
   WriteDword(p,1);               // always 1 (unknown);
   WriteDword(p,mod13value);      //a value that increments with 13.
   WriteDword(p,mod13value);      //a value that increments with 13.
   mod13value:=mod13value+13;
   mod13value:=mod13value+13;
@@ -2158,32 +2224,36 @@ begin
   Result:=blk-start;
   Result:=blk-start;
 end;
 end;
 
 
-procedure CombineWithChildren(ParentItem:TChmSiteMapItem;Str:WideString;commaatposition:integer;first:boolean);
+procedure CombineWithChildren(ParentItem:TChmSiteMapItem;Str:UnicodeString;commaatposition:integer;level:integer);
 var i    : Integer;
 var i    : Integer;
-    Item : TChmSiteMapItem;
-begin
-  if ParentItem.Children.Count = 0 Then
-    Begin
+    llItem : TChmSiteMapItem;
+begin
+   str:=StringReplace(str, '&x27;', '', [rfReplaceAll]);
+   {$ifdef binindex}
+     writeln('i:',level,' ',str);
+   {$endif}
+//  if ParentItem.Children.Count = 0 Then
+//    Begin
      // comment/fix next
      // comment/fix next
      //   if commatposition=length(str) then commaatposition:=0;
      //   if commatposition=length(str) then commaatposition:=0;
-       if first then
-        CreateEntry(ParentItem,Str,0)
+       if level=0 then
+        CreateEntry(ParentItem,Str,0,level)
        else
        else
-        CreateEntry(ParentItem,Str,commaatposition);
-    End
-  Else
+        CreateEntry(ParentItem,Str,commaatposition,level);
+//    End
+//  Else
     for i:=0 to ParentItem.Children.Count-1 do
     for i:=0 to ParentItem.Children.Count-1 do
       begin
       begin
-        item := TChmSiteMapItem(ParentItem.Children.Item[i]);
-        if first Then
-          CombineWithChildren(Item,Str+', '+item.text,commaatposition+2,false)
-        else
-          CombineWithChildren(Item,Str+', '+item.text,commaatposition,false);
+        llitem := TChmSiteMapItem(ParentItem.Children.Item[i]);
+{        if level=0 Then
+          CombineWithChildren(Item,str+', '+item.text,0,level+1)
+        else}
+          CombineWithChildren(llItem,Str+', '+llitem.text,length(str)+2,level+1);
       end;
       end;
 end;
 end;
 
 
 Var i             : Integer;
 Var i             : Integer;
-    Key           : WideString;
+    Key           : UnicodeString;
     Item          : TChmSiteMapItem;
     Item          : TChmSiteMapItem;
     ListingBlocks : Integer;
     ListingBlocks : Integer;
     EntryBytes    : Integer;
     EntryBytes    : Integer;
@@ -2204,6 +2274,7 @@ begin
   {$ifdef binindex}
   {$ifdef binindex}
     writeln('starting index');
     writeln('starting index');
   {$endif}
   {$endif}
+  ASiteMap.sort(@indexitemcompare);
   IndexStream:=TMemoryStream.Create;
   IndexStream:=TMemoryStream.Create;
   indexstream.size:=sizeof(TBTreeHeader);
   indexstream.size:=sizeof(TBTreeHeader);
   IndexStream.position:=Sizeof(TBTreeHeader);
   IndexStream.position:=Sizeof(TBTreeHeader);
@@ -2251,7 +2322,7 @@ begin
       // so we can see if Windows loads the binary or textual index.
       // so we can see if Windows loads the binary or textual index.
       CombineWithChildren(Item,Key+'2',length(key)+1,true);
       CombineWithChildren(Item,Key+'2',length(key)+1,true);
       {$else}
       {$else}
-      CombineWithChildren(Item,Key,length(key),true);
+      CombineWithChildren(Item,Key,length(key),0);
       {$endif}
       {$endif}
     end;
     end;
   PrepareCurrentBlock(True);     // flush last listing block.
   PrepareCurrentBlock(True);     // flush last listing block.
@@ -2420,7 +2491,6 @@ begin
   PostAddStreamToArchive(AName, '/', AStream);
   PostAddStreamToArchive(AName, '/', AStream);
 end;
 end;
 
 
-
 procedure TChmWriter.AddContext(AContext: DWord; ATopic: String);
 procedure TChmWriter.AddContext(AContext: DWord; ATopic: String);
 var
 var
   Offset: DWord;
   Offset: DWord;
@@ -2448,7 +2518,6 @@ begin
 end;
 end;
 
 
 procedure TChmWriter.Setwindows(AWindowList: TObjectList);
 procedure TChmWriter.Setwindows(AWindowList: TObjectList);
-
 var i : integer;
 var i : integer;
     x : TCHMWindow;
     x : TCHMWindow;
 begin
 begin

+ 2 - 0
packages/fcl-base/examples/README.txt

@@ -76,3 +76,5 @@ testtimer.pp Test for TFPTimer (MVC)
 testini.pp   Test/Demo for inifiles, ReadSectionValues.
 testini.pp   Test/Demo for inifiles, ReadSectionValues.
 contit.pp    Test/Demo for iterators in contnr.pp
 contit.pp    Test/Demo for iterators in contnr.pp
 csvbom.pp    Test/Demo for BOM detection in CSV document. (needs databom.txt)
 csvbom.pp    Test/Demo for BOM detection in CSV document. (needs databom.txt)
+testappexit.pp Test/Demo for TApplication exit code handling. (ExitCode and ExceptionExitcode)
+demoio.pp    Demo for AssignStream from streamio unit.

+ 27 - 0
packages/fcl-base/examples/demoio.pp

@@ -0,0 +1,27 @@
+program demoio;
+
+{$mode objfpc}
+{$h+}
+uses streamio, classes;
+
+Var
+  S : TStringStream;
+  F : Text;
+  a,b,c : Integer;
+
+begin
+  a:=1;
+  b:=2;
+  c:=a+b;
+  S:=TStringStream.Create('');
+  try
+    AssignStream(F,S);
+    Rewrite(F);
+    Writeln(F,'Hello World !');
+    Writeln(F,a:3,b:3,c:3);
+    CloseFile(F);
+    Writeln(S.DataString); 
+  finally
+    S.Free;
+  end;
+end.

+ 32 - 0
packages/fcl-base/examples/testappexit.pp

@@ -0,0 +1,32 @@
+program testappexit;
+
+uses sysutils,custapp;
+
+type
+  TApplication = Class(TCustomApplication)
+    Procedure DoRun; override;
+  end;
+  
+Procedure TApplication.DoRun;
+
+begin
+  ExceptionExitCode:=9;
+  If ParamStr(1)='-h' then
+    Terminate(10)
+  else if Paramstr(1)='-e' then
+    Raise Exception.Create('Stopping with exception')
+  else
+    Writeln('Normal stop');  
+  Terminate;  
+end;
+
+begin
+  With TApplication.Create(Nil) do
+    try
+      StopOnException:=True;
+      Initialize;
+      Run;
+    finally
+      Free;
+    end;     
+end.

+ 28 - 1
packages/fcl-image/src/fpwritetiff.pas

@@ -82,6 +82,7 @@ type
     fStream: TStream;
     fStream: TStream;
     fPosition: DWord;
     fPosition: DWord;
     procedure ClearEntries;
     procedure ClearEntries;
+    procedure SortEntries;
     procedure WriteTiff;
     procedure WriteTiff;
     procedure WriteHeader;
     procedure WriteHeader;
     procedure WriteIFDs;
     procedure WriteIFDs;
@@ -257,6 +258,29 @@ begin
   WriteDWord(8);
   WriteDWord(8);
 end;
 end;
 
 
+procedure TFPWriterTiff.SortEntries;
+var
+  i, j: Integer;
+  Entry: TTiffWriterEntry;
+  List: TFPList;
+begin
+  // Sort Entries by Tag Value Ascending
+  for i:= 0 to FEntries.Count-1 do begin
+    List := TFPList(FEntries[i]);
+    j := 0;
+    repeat
+        if TTiffWriterEntry(List[j]).Tag > TTiffWriterEntry(List[j+1]).Tag then begin
+          Entry := TTiffWriterEntry(List[j+1]);
+          List[j] := List[j+1];
+          List[j+1] := Entry;
+          j := 0;
+        end
+        else
+            j := j+1;
+    until j >= List.Count-2;
+  end;
+end;
+
 procedure TFPWriterTiff.WriteIFDs;
 procedure TFPWriterTiff.WriteIFDs;
 var
 var
   i: Integer;
   i: Integer;
@@ -265,6 +289,8 @@ var
   Entry: TTiffWriterEntry;
   Entry: TTiffWriterEntry;
   NextIFDPos: DWord;
   NextIFDPos: DWord;
 begin
 begin
+  // Sort the Entries before writing!
+  SortEntries;
   for i:=0 to FEntries.Count-1 do begin
   for i:=0 to FEntries.Count-1 do begin
     List:=TFPList(FEntries[i]);
     List:=TFPList(FEntries[i]);
     // write count
     // write count
@@ -553,7 +579,8 @@ begin
         TilesDown:=(OrientedHeight+IFD.TileLength{%H-}-1) div IFD.TileLength;
         TilesDown:=(OrientedHeight+IFD.TileLength{%H-}-1) div IFD.TileLength;
         ChunkCount:=TilesAcross*TilesDown;
         ChunkCount:=TilesAcross*TilesDown;
         {$IFDEF FPC_Debug_Image}
         {$IFDEF FPC_Debug_Image}
-        writeln('TFPWriterTiff.AddImage BitsPerPixel=',BitsPerPixel,' OrientedWidth=',OrientedWidth,' OrientedHeight=',OrientedHeight,' TileWidth=',IFD.TileWidth,' TileLength=',IFD.TileLength,' TilesAcross=',TilesAcross,' TilesDown=',TilesDown,' ChunkCount=',ChunkCount);
+        writeln('TFPWriterTiff.AddImage BitsPerPixel=',BitsPerPixel,' OrientedWidth=',OrientedWidth,' OrientedHeight=',OrientedHeight,' TileWidth=',IFD.TileWidth,' TileLength=',IFD.TileLength,' TilesAcross=',TilesAcross,' TilesDown=',TilesDown,' ChunkCoun
+t=',ChunkCount);
         {$ENDIF}
         {$ENDIF}
       end else begin
       end else begin
         ChunkCount:=(OrientedHeight+IFD.RowsPerStrip{%H-}-1) div IFD.RowsPerStrip;
         ChunkCount:=(OrientedHeight+IFD.RowsPerStrip{%H-}-1) div IFD.RowsPerStrip;

+ 4 - 6
packages/fcl-image/src/freetype.pp

@@ -31,7 +31,7 @@ uses sysutils, classes, {$IFDEF DYNAMIC}freetypehdyn{$ELSE}freetypeh{$ENDIF}, FP
               fontfiles and faces available in a fontfile }
               fontfiles and faces available in a fontfile }
 
 
 // determine if file comparison need to be case sensitive or not
 // determine if file comparison need to be case sensitive or not
-{$ifdef WIN32}
+{$ifdef windows}
   {$undef CaseSense}
   {$undef CaseSense}
 {$else}
 {$else}
   {$define CaseSense}
   {$define CaseSense}
@@ -200,8 +200,6 @@ const
 
 
 implementation
 implementation
 
 
-{$IFDEF win32}uses dos;{$ENDIF}
-
 procedure FTError (Event:string; Err:integer);
 procedure FTError (Event:string; Err:integer);
 begin
 begin
   raise FreeTypeException.CreateFmt (sErrFreeType, [Err,Event]);
   raise FreeTypeException.CreateFmt (sErrFreeType, [Err,Event]);
@@ -1032,15 +1030,15 @@ begin
   aRect := FBounds;
   aRect := FBounds;
 end;
 end;
 
 
-{$ifdef win32}
+{$ifdef WINDOWS}
 procedure SetWindowsFontPath;
 procedure SetWindowsFontPath;
 begin
 begin
-  DefaultSearchPath := includetrailingbackslash(GetEnv('windir')) + 'fonts';
+  DefaultSearchPath := includetrailingbackslash(GetEnvironmentVariable('windir')) + 'fonts';
 end;
 end;
 {$endif}
 {$endif}
 
 
 initialization
 initialization
-  {$ifdef win32}
+  {$ifdef WINDOWS}
   SetWindowsFontPath;
   SetWindowsFontPath;
   {$endif}
   {$endif}
 end.
 end.

+ 1 - 1
packages/fcl-image/src/libfreetype.inc

@@ -6,7 +6,7 @@ Const
 
 
 // Windows
 // Windows
 {$ifdef windows}
 {$ifdef windows}
-  FreeTypeDLL = 'freetype-6.dll';   // version 2.1.4
+  FreeTypeDLL = 'freetype.dll';
   {$define ft_found_platform}
   {$define ft_found_platform}
 {$endif}
 {$endif}
 
 

+ 222 - 221
packages/fcl-passrc/src/pasresolver.pp

@@ -1474,7 +1474,6 @@ type
     procedure ResolveImplElement(El: TPasImplElement); virtual;
     procedure ResolveImplElement(El: TPasImplElement); virtual;
     procedure ResolveImplCaseOf(CaseOf: TPasImplCaseOf); virtual;
     procedure ResolveImplCaseOf(CaseOf: TPasImplCaseOf); virtual;
     procedure ResolveImplLabelMark(Mark: TPasImplLabelMark); virtual;
     procedure ResolveImplLabelMark(Mark: TPasImplLabelMark); virtual;
-    procedure ResolveImplForLoop(Loop: TPasImplForLoop); virtual;
     procedure ResolveImplWithDo(El: TPasImplWithDo); virtual;
     procedure ResolveImplWithDo(El: TPasImplWithDo); virtual;
     procedure ResolveImplAsm(El: TPasImplAsmStatement); virtual;
     procedure ResolveImplAsm(El: TPasImplAsmStatement); virtual;
     procedure ResolveImplAssign(El: TPasImplAssign); virtual;
     procedure ResolveImplAssign(El: TPasImplAssign); virtual;
@@ -1534,6 +1533,7 @@ type
     procedure FinishExceptOnExpr; virtual;
     procedure FinishExceptOnExpr; virtual;
     procedure FinishExceptOnStatement; virtual;
     procedure FinishExceptOnStatement; virtual;
     procedure FinishWithDo(El: TPasImplWithDo); virtual;
     procedure FinishWithDo(El: TPasImplWithDo); virtual;
+    procedure FinishForLoopHeader(Loop: TPasImplForLoop); virtual;
     procedure FinishDeclaration(El: TPasElement); virtual;
     procedure FinishDeclaration(El: TPasElement); virtual;
     procedure FinishVariable(El: TPasVariable); virtual;
     procedure FinishVariable(El: TPasVariable); virtual;
     procedure FinishProperty(PropEl: TPasProperty); virtual;
     procedure FinishProperty(PropEl: TPasProperty); virtual;
@@ -6440,6 +6440,224 @@ begin
   PopWithScope(El);
   PopWithScope(El);
 end;
 end;
 
 
+procedure TPasResolver.FinishForLoopHeader(Loop: TPasImplForLoop);
+var
+  VarResolved, StartResolved, EndResolved,
+    OrigStartResolved: TPasResolverResult;
+  EnumeratorFound, HasInValues: Boolean;
+  InRange, VarRange: TResEvalValue;
+  InRangeInt, VarRangeInt: TResEvalRangeInt;
+  bt: TResolverBaseType;
+  TypeEl, ElType: TPasType;
+  C: TClass;
+begin
+  CreateScope(Loop,TPasForLoopScope);
+
+  // loop var
+  ResolveExpr(Loop.VariableName,rraReadAndAssign);
+  ComputeElement(Loop.VariableName,VarResolved,[rcNoImplicitProc,rcSetReferenceFlags]);
+  if not ResolvedElCanBeVarParam(VarResolved,Loop.VariableName) then
+    RaiseVarExpected(20170216151955,Loop.VariableName,VarResolved.IdentEl);
+
+  // resolve start expression
+  ResolveExpr(Loop.StartExpr,rraRead);
+  ComputeElement(Loop.StartExpr,StartResolved,[rcSetReferenceFlags]);
+
+  case Loop.LoopType of
+  ltNormal,ltDown:
+    begin
+    // start value
+    if CheckAssignResCompatibility(VarResolved,StartResolved,Loop.StartExpr,true)=cIncompatible then
+      RaiseIncompatibleTypeRes(20170216151958,nIncompatibleTypesGotExpected,
+        [],StartResolved,VarResolved,Loop.StartExpr);
+    CheckAssignExprRange(VarResolved,Loop.StartExpr);
+
+    // end value
+    ResolveExpr(Loop.EndExpr,rraRead);
+    ComputeElement(Loop.EndExpr,EndResolved,[rcSetReferenceFlags]);
+    if CheckAssignResCompatibility(VarResolved,EndResolved,Loop.EndExpr,false)=cIncompatible then
+      RaiseIncompatibleTypeRes(20170216152001,nIncompatibleTypesGotExpected,
+        [],EndResolved,VarResolved,Loop.EndExpr);
+    CheckAssignExprRange(VarResolved,Loop.EndExpr);
+    end;
+  ltIn:
+    begin
+    // check range
+    EnumeratorFound:=CheckForIn(Loop,VarResolved,StartResolved);
+    if (not EnumeratorFound)
+        and not (StartResolved.IdentEl is TPasType)
+        and (rrfReadable in StartResolved.Flags) then
+      begin
+      EnumeratorFound:=CheckForInClassOrRec(Loop,VarResolved,StartResolved);
+      end;
+
+    if not EnumeratorFound then
+      begin
+      VarRange:=nil;
+      InRange:=nil;
+      try
+        OrigStartResolved:=StartResolved;
+        if StartResolved.IdentEl is TPasType then
+          begin
+          // e.g. for e in TEnum do
+          TypeEl:=StartResolved.LoTypeEl;
+          if TypeEl is TPasArrayType then
+            begin
+            if length(TPasArrayType(TypeEl).Ranges)=1 then
+              InRange:=Eval(TPasArrayType(TypeEl).Ranges[0],[refConst]);
+            end;
+          if InRange=nil then
+            InRange:=EvalTypeRange(TypeEl,[]);
+          {$IFDEF VerbosePasResolver}
+          {AllowWriteln}
+          if InRange<>nil then
+            writeln('TPasResolver.ResolveImplForLoop in type: InRange=',InRange.AsDebugString)
+          else
+            writeln('TPasResolver.ResolveImplForLoop in type: InRange=nil');
+          {AllowWriteln-}
+          {$ENDIF}
+          end
+        else if rrfReadable in StartResolved.Flags then
+          begin
+          // value  (variable or expression)
+          bt:=StartResolved.BaseType;
+          if bt in [btSet,btArrayOrSet] then
+            begin
+            if (StartResolved.IdentEl=nil) and (StartResolved.ExprEl<>nil) then
+              InRange:=Eval(StartResolved.ExprEl,[]);
+            if InRange=nil then
+              InRange:=EvalTypeRange(StartResolved.LoTypeEl,[]);
+            end
+          else if bt=btContext then
+            begin
+            TypeEl:=StartResolved.LoTypeEl;
+            C:=TypeEl.ClassType;
+            if C=TPasArrayType then
+              begin
+              ElType:=GetArrayElType(TPasArrayType(TypeEl));
+              ComputeElement(ElType,StartResolved,[rcType]);
+              StartResolved.Flags:=OrigStartResolved.Flags*[rrfReadable,rrfWritable];
+              if CheckAssignResCompatibility(VarResolved,StartResolved,Loop.StartExpr,true)=cIncompatible then
+                RaiseIncompatibleTypeRes(20171112210138,nIncompatibleTypesGotExpected,
+                  [],StartResolved,VarResolved,Loop.StartExpr);
+              EnumeratorFound:=true;
+              end;
+            end
+          else
+            begin
+            bt:=GetActualBaseType(bt);
+            case bt of
+            {$ifdef FPC_HAS_CPSTRING}
+            btAnsiString:
+              InRange:=TResEvalRangeInt.CreateValue(revskChar,nil,0,$ff);
+            {$endif}
+            btUnicodeString:
+              InRange:=TResEvalRangeInt.CreateValue(revskChar,nil,0,$ffff);
+            end;
+            end;
+          end;
+        if (not EnumeratorFound) and (InRange<>nil) then
+          begin
+          // for v in <constant> do
+          // -> check if same type
+          VarRange:=EvalTypeRange(VarResolved.LoTypeEl,[]);
+          if VarRange=nil then
+            RaiseXExpectedButYFound(20171109191528,'range',
+                         GetResolverResultDescription(VarResolved),Loop.VariableName);
+          //writeln('TPasResolver.ResolveImplForLoop ForIn VarRange=',VarRange.AsDebugString);
+          //writeln('TPasResolver.ResolveImplForLoop ForIn InRange=',InRange.AsDebugString,' ElType=',GetResolverResultDbg(StartResolved));
+          case InRange.Kind of
+          revkRangeInt,revkSetOfInt:
+            begin
+            InRangeInt:=TResEvalRangeInt(InRange);
+            case VarRange.Kind of
+            revkRangeInt:
+              begin
+              VarRangeInt:=TResEvalRangeInt(VarRange);
+              HasInValues:=(InRange.Kind<>revkSetOfInt) or (length(TResEvalSet(InRange).Ranges)>0);
+              case InRangeInt.ElKind of
+                revskEnum:
+                  if (VarRangeInt.ElKind<>revskEnum)
+                      or not IsSameType(InRangeInt.ElType,VarRangeInt.ElType,prraAlias) then
+                    RaiseXExpectedButYFound(20171109200752,GetTypeDescription(InRangeInt.ElType),
+                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
+                revskInt:
+                  if VarRangeInt.ElKind<>revskInt then
+                    RaiseXExpectedButYFound(20171109200752,'integer',
+                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
+                revskChar:
+                  if VarRangeInt.ElKind<>revskChar then
+                    RaiseXExpectedButYFound(20171109200753,'char',
+                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
+                revskBool:
+                  if VarRangeInt.ElKind<>revskBool then
+                    RaiseXExpectedButYFound(20171109200754,'boolean',
+                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
+              else
+                if HasInValues then
+                  RaiseNotYetImplemented(20171109200954,Loop.StartExpr);
+              end;
+              if HasInValues then
+                begin
+                if (VarRangeInt.RangeStart>InRangeInt.RangeStart) then
+                  begin
+                  {$IFDEF VerbosePasResolver}
+                  writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRangeInt.AsDebugString,' ',InRangeInt.AsDebugString);
+                  {$ENDIF}
+                  fExprEvaluator.EmitRangeCheckConst(20171109201428,
+                    InRangeInt.ElementAsString(InRangeInt.RangeStart),
+                    VarRangeInt.ElementAsString(VarRangeInt.RangeStart),
+                    VarRangeInt.ElementAsString(VarRangeInt.RangeEnd),Loop.VariableName,mtError);
+                  end;
+                if (VarRangeInt.RangeEnd<InRangeInt.RangeEnd) then
+                  begin
+                  {$IFDEF VerbosePasResolver}
+                  writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRangeInt.AsDebugString,' ',InRangeInt.AsDebugString);
+                  {$ENDIF}
+                  fExprEvaluator.EmitRangeCheckConst(20171109201429,
+                    InRangeInt.ElementAsString(InRangeInt.RangeEnd),
+                    VarRangeInt.ElementAsString(VarRangeInt.RangeStart),
+                    VarRangeInt.ElementAsString(VarRangeInt.RangeEnd),Loop.VariableName,mtError);
+                  end;
+                end;
+              EnumeratorFound:=true;
+              end;
+            else
+              {$IFDEF VerbosePasResolver}
+              writeln('TPasResolver.ResolveImplForLoop ForIn VarRange=',VarRange.AsDebugString);
+              {$ENDIF}
+            end;
+            end;
+          else
+            {$IFDEF VerbosePasResolver}
+            writeln('TPasResolver.ResolveImplForLoop ForIn InRange=',InRange.AsDebugString);
+            {$ENDIF}
+          end;
+          end;
+        if not EnumeratorFound then
+          begin
+          {$IFDEF VerbosePasResolver}
+          {AllowWriteln}
+          writeln('TPasResolver.ResolveImplForLoop StartResolved=',GetResolverResultDbg(StartResolved));
+          if VarRange<>nil then
+            writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRange.AsDebugString);
+          {AllowWriteln-}
+          {$ENDIF}
+          RaiseMsg(20171108223818,nCannotFindEnumeratorForType,sCannotFindEnumeratorForType,
+            [GetBaseDescription(OrigStartResolved)],Loop.StartExpr);
+          end;
+      finally
+        ReleaseEvalValue(VarRange);
+        ReleaseEvalValue(InRange);
+      end;
+      end;
+
+    end;
+  else
+    RaiseNotYetImplemented(20171108221334,Loop);
+  end;
+end;
+
 procedure TPasResolver.FinishDeclaration(El: TPasElement);
 procedure TPasResolver.FinishDeclaration(El: TPasElement);
 var
 var
   C: TClass;
   C: TClass;
@@ -8003,7 +8221,8 @@ begin
   else if C=TPasImplLabelMark then
   else if C=TPasImplLabelMark then
     ResolveImplLabelMark(TPasImplLabelMark(El))
     ResolveImplLabelMark(TPasImplLabelMark(El))
   else if C=TPasImplForLoop then
   else if C=TPasImplForLoop then
-    ResolveImplForLoop(TPasImplForLoop(El))
+    // the header was already resolved
+    ResolveImplElement(TPasImplForLoop(El).Body)
   else if C=TPasImplTry then
   else if C=TPasImplTry then
     begin
     begin
     ResolveImplBlock(TPasImplTry(El));
     ResolveImplBlock(TPasImplTry(El));
@@ -8346,225 +8565,6 @@ begin
   RaiseNotYetImplemented(20161014141636,Mark);
   RaiseNotYetImplemented(20161014141636,Mark);
 end;
 end;
 
 
-procedure TPasResolver.ResolveImplForLoop(Loop: TPasImplForLoop);
-var
-  VarResolved, StartResolved, EndResolved,
-    OrigStartResolved: TPasResolverResult;
-  EnumeratorFound, HasInValues: Boolean;
-  InRange, VarRange: TResEvalValue;
-  InRangeInt, VarRangeInt: TResEvalRangeInt;
-  bt: TResolverBaseType;
-  TypeEl, ElType: TPasType;
-  C: TClass;
-begin
-  CreateScope(Loop,TPasForLoopScope);
-
-  // loop var
-  ResolveExpr(Loop.VariableName,rraReadAndAssign);
-  ComputeElement(Loop.VariableName,VarResolved,[rcNoImplicitProc,rcSetReferenceFlags]);
-  if not ResolvedElCanBeVarParam(VarResolved,Loop.VariableName) then
-    RaiseVarExpected(20170216151955,Loop.VariableName,VarResolved.IdentEl);
-
-  // resolve start expression
-  ResolveExpr(Loop.StartExpr,rraRead);
-  ComputeElement(Loop.StartExpr,StartResolved,[rcSetReferenceFlags]);
-
-  case Loop.LoopType of
-  ltNormal,ltDown:
-    begin
-    // start value
-    if CheckAssignResCompatibility(VarResolved,StartResolved,Loop.StartExpr,true)=cIncompatible then
-      RaiseIncompatibleTypeRes(20170216151958,nIncompatibleTypesGotExpected,
-        [],StartResolved,VarResolved,Loop.StartExpr);
-    CheckAssignExprRange(VarResolved,Loop.StartExpr);
-
-    // end value
-    ResolveExpr(Loop.EndExpr,rraRead);
-    ComputeElement(Loop.EndExpr,EndResolved,[rcSetReferenceFlags]);
-    if CheckAssignResCompatibility(VarResolved,EndResolved,Loop.EndExpr,false)=cIncompatible then
-      RaiseIncompatibleTypeRes(20170216152001,nIncompatibleTypesGotExpected,
-        [],EndResolved,VarResolved,Loop.EndExpr);
-    CheckAssignExprRange(VarResolved,Loop.EndExpr);
-    end;
-  ltIn:
-    begin
-    // check range
-    EnumeratorFound:=CheckForIn(Loop,VarResolved,StartResolved);
-    if (not EnumeratorFound)
-        and not (StartResolved.IdentEl is TPasType)
-        and (rrfReadable in StartResolved.Flags) then
-      begin
-      EnumeratorFound:=CheckForInClassOrRec(Loop,VarResolved,StartResolved);
-      end;
-
-    if not EnumeratorFound then
-      begin
-      VarRange:=nil;
-      InRange:=nil;
-      try
-        OrigStartResolved:=StartResolved;
-        if StartResolved.IdentEl is TPasType then
-          begin
-          // e.g. for e in TEnum do
-          TypeEl:=StartResolved.LoTypeEl;
-          if TypeEl is TPasArrayType then
-            begin
-            if length(TPasArrayType(TypeEl).Ranges)=1 then
-              InRange:=Eval(TPasArrayType(TypeEl).Ranges[0],[refConst]);
-            end;
-          if InRange=nil then
-            InRange:=EvalTypeRange(TypeEl,[]);
-          {$IFDEF VerbosePasResolver}
-          {AllowWriteln}
-          if InRange<>nil then
-            writeln('TPasResolver.ResolveImplForLoop in type: InRange=',InRange.AsDebugString)
-          else
-            writeln('TPasResolver.ResolveImplForLoop in type: InRange=nil');
-          {AllowWriteln-}
-          {$ENDIF}
-          end
-        else if rrfReadable in StartResolved.Flags then
-          begin
-          // value  (variable or expression)
-          bt:=StartResolved.BaseType;
-          if bt in [btSet,btArrayOrSet] then
-            begin
-            if (StartResolved.IdentEl=nil) and (StartResolved.ExprEl<>nil) then
-              InRange:=Eval(StartResolved.ExprEl,[]);
-            if InRange=nil then
-              InRange:=EvalTypeRange(StartResolved.LoTypeEl,[]);
-            end
-          else if bt=btContext then
-            begin
-            TypeEl:=StartResolved.LoTypeEl;
-            C:=TypeEl.ClassType;
-            if C=TPasArrayType then
-              begin
-              ElType:=GetArrayElType(TPasArrayType(TypeEl));
-              ComputeElement(ElType,StartResolved,[rcType]);
-              StartResolved.Flags:=OrigStartResolved.Flags*[rrfReadable,rrfWritable];
-              if CheckAssignResCompatibility(VarResolved,StartResolved,Loop.StartExpr,true)=cIncompatible then
-                RaiseIncompatibleTypeRes(20171112210138,nIncompatibleTypesGotExpected,
-                  [],StartResolved,VarResolved,Loop.StartExpr);
-              EnumeratorFound:=true;
-              end;
-            end
-          else
-            begin
-            bt:=GetActualBaseType(bt);
-            case bt of
-            {$ifdef FPC_HAS_CPSTRING}
-            btAnsiString:
-              InRange:=TResEvalRangeInt.CreateValue(revskChar,nil,0,$ff);
-            {$endif}
-            btUnicodeString:
-              InRange:=TResEvalRangeInt.CreateValue(revskChar,nil,0,$ffff);
-            end;
-            end;
-          end;
-        if (not EnumeratorFound) and (InRange<>nil) then
-          begin
-          // for v in <constant> do
-          // -> check if same type
-          VarRange:=EvalTypeRange(VarResolved.LoTypeEl,[]);
-          if VarRange=nil then
-            RaiseXExpectedButYFound(20171109191528,'range',
-                         GetResolverResultDescription(VarResolved),Loop.VariableName);
-          //writeln('TPasResolver.ResolveImplForLoop ForIn VarRange=',VarRange.AsDebugString);
-          //writeln('TPasResolver.ResolveImplForLoop ForIn InRange=',InRange.AsDebugString,' ElType=',GetResolverResultDbg(StartResolved));
-          case InRange.Kind of
-          revkRangeInt,revkSetOfInt:
-            begin
-            InRangeInt:=TResEvalRangeInt(InRange);
-            case VarRange.Kind of
-            revkRangeInt:
-              begin
-              VarRangeInt:=TResEvalRangeInt(VarRange);
-              HasInValues:=(InRange.Kind<>revkSetOfInt) or (length(TResEvalSet(InRange).Ranges)>0);
-              case InRangeInt.ElKind of
-                revskEnum:
-                  if (VarRangeInt.ElKind<>revskEnum)
-                      or not IsSameType(InRangeInt.ElType,VarRangeInt.ElType,prraAlias) then
-                    RaiseXExpectedButYFound(20171109200752,GetTypeDescription(InRangeInt.ElType),
-                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
-                revskInt:
-                  if VarRangeInt.ElKind<>revskInt then
-                    RaiseXExpectedButYFound(20171109200752,'integer',
-                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
-                revskChar:
-                  if VarRangeInt.ElKind<>revskChar then
-                    RaiseXExpectedButYFound(20171109200753,'char',
-                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
-                revskBool:
-                  if VarRangeInt.ElKind<>revskBool then
-                    RaiseXExpectedButYFound(20171109200754,'boolean',
-                      GetResolverResultDescription(VarResolved,true),loop.VariableName);
-              else
-                if HasInValues then
-                  RaiseNotYetImplemented(20171109200954,Loop.StartExpr);
-              end;
-              if HasInValues then
-                begin
-                if (VarRangeInt.RangeStart>InRangeInt.RangeStart) then
-                  begin
-                  {$IFDEF VerbosePasResolver}
-                  writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRangeInt.AsDebugString,' ',InRangeInt.AsDebugString);
-                  {$ENDIF}
-                  fExprEvaluator.EmitRangeCheckConst(20171109201428,
-                    InRangeInt.ElementAsString(InRangeInt.RangeStart),
-                    VarRangeInt.ElementAsString(VarRangeInt.RangeStart),
-                    VarRangeInt.ElementAsString(VarRangeInt.RangeEnd),Loop.VariableName,mtError);
-                  end;
-                if (VarRangeInt.RangeEnd<InRangeInt.RangeEnd) then
-                  begin
-                  {$IFDEF VerbosePasResolver}
-                  writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRangeInt.AsDebugString,' ',InRangeInt.AsDebugString);
-                  {$ENDIF}
-                  fExprEvaluator.EmitRangeCheckConst(20171109201429,
-                    InRangeInt.ElementAsString(InRangeInt.RangeEnd),
-                    VarRangeInt.ElementAsString(VarRangeInt.RangeStart),
-                    VarRangeInt.ElementAsString(VarRangeInt.RangeEnd),Loop.VariableName,mtError);
-                  end;
-                end;
-              EnumeratorFound:=true;
-              end;
-            else
-              {$IFDEF VerbosePasResolver}
-              writeln('TPasResolver.ResolveImplForLoop ForIn VarRange=',VarRange.AsDebugString);
-              {$ENDIF}
-            end;
-            end;
-          else
-            {$IFDEF VerbosePasResolver}
-            writeln('TPasResolver.ResolveImplForLoop ForIn InRange=',InRange.AsDebugString);
-            {$ENDIF}
-          end;
-          end;
-        if not EnumeratorFound then
-          begin
-          {$IFDEF VerbosePasResolver}
-          {AllowWriteln}
-          writeln('TPasResolver.ResolveImplForLoop StartResolved=',GetResolverResultDbg(StartResolved));
-          if VarRange<>nil then
-            writeln('TPasResolver.ResolveImplForLoop VarRange=',VarRange.AsDebugString);
-          {AllowWriteln-}
-          {$ENDIF}
-          RaiseMsg(20171108223818,nCannotFindEnumeratorForType,sCannotFindEnumeratorForType,
-            [GetBaseDescription(OrigStartResolved)],Loop.StartExpr);
-          end;
-      finally
-        ReleaseEvalValue(VarRange);
-        ReleaseEvalValue(InRange);
-      end;
-      end;
-
-    end;
-  else
-    RaiseNotYetImplemented(20171108221334,Loop);
-  end;
-  ResolveImplElement(Loop.Body);
-end;
-
 procedure TPasResolver.ResolveImplWithDo(El: TPasImplWithDo);
 procedure TPasResolver.ResolveImplWithDo(El: TPasImplWithDo);
 // Note: the expressions were already resolved during parsing
 // Note: the expressions were already resolved during parsing
 //  and the scopes were already stored in a TPasWithScope.
 //  and the scopes were already stored in a TPasWithScope.
@@ -16539,6 +16539,7 @@ begin
   stExceptOnExpr: FinishExceptOnExpr;
   stExceptOnExpr: FinishExceptOnExpr;
   stExceptOnStatement: FinishExceptOnStatement;
   stExceptOnStatement: FinishExceptOnStatement;
   stWithExpr: FinishWithDo(El as TPasImplWithDo);
   stWithExpr: FinishWithDo(El as TPasImplWithDo);
+  stForLoopHeader: FinishForLoopHeader(El as TPasImplForLoop);
   stDeclaration: FinishDeclaration(El);
   stDeclaration: FinishDeclaration(El);
   stAncestors: FinishAncestors(El as TPasClassType);
   stAncestors: FinishAncestors(El as TPasClassType);
   stInitialFinalization: FinishInitialFinalization(El as TPasImplBlock);
   stInitialFinalization: FinishInitialFinalization(El as TPasImplBlock);

+ 2 - 0
packages/fcl-passrc/src/pparser.pp

@@ -174,6 +174,7 @@ type
     stWithExpr, // calls BeginScope after parsing every WITH-expression
     stWithExpr, // calls BeginScope after parsing every WITH-expression
     stExceptOnExpr,
     stExceptOnExpr,
     stExceptOnStatement,
     stExceptOnStatement,
+    stForLoopHeader,
     stDeclaration, // e.g. a TPasProperty, TPasVariable, TPasArgument, ...
     stDeclaration, // e.g. a TPasProperty, TPasVariable, TPasArgument, ...
     stAncestors, // the list of ancestors and interfaces of a class
     stAncestors, // the list of ancestors and interfaces of a class
     stInitialFinalization
     stInitialFinalization
@@ -5809,6 +5810,7 @@ begin
           TPasImplForLoop(El).LoopType:=lt;
           TPasImplForLoop(El).LoopType:=lt;
           if (CurToken<>tkDo) then
           if (CurToken<>tkDo) then
             ParseExcTokenError(TokenInfos[tkDo]);
             ParseExcTokenError(TokenInfos[tkDo]);
+          Engine.FinishScope(stForLoopHeader,El);
           CreateBlock(TPasImplForLoop(El));
           CreateBlock(TPasImplForLoop(El));
           El:=nil;
           El:=nil;
           //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
           //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);

+ 22 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -470,6 +470,7 @@ type
     Procedure TestAnonymousProc_With;
     Procedure TestAnonymousProc_With;
     Procedure TestAnonymousProc_ExceptOn;
     Procedure TestAnonymousProc_ExceptOn;
     Procedure TestAnonymousProc_Nested;
     Procedure TestAnonymousProc_Nested;
+    Procedure TestAnonymousProc_ForLoop;
 
 
     // record
     // record
     Procedure TestRecord;
     Procedure TestRecord;
@@ -7793,6 +7794,27 @@ begin
   ParseProgram;
   ParseProgram;
 end;
 end;
 
 
+procedure TTestResolver.TestAnonymousProc_ForLoop;
+begin
+  StartProgram(false);
+  Add([
+  'type TProc = reference to procedure;',
+  'procedure Foo(p: TProc);',
+  'begin',
+  'end;',
+  'procedure DoIt;',
+  'var i: word;',
+  '  a: word;',
+  'begin',
+  '  for i:=1 to 10 do begin',
+  '    Foo(procedure begin a:=3; end);',
+  '  end;',
+  'end;',
+  'begin',
+  '  DoIt;']);
+  ParseProgram;
+end;
+
 procedure TTestResolver.TestRecord;
 procedure TTestResolver.TestRecord;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 1 - 1
packages/pastojs/src/fppas2js.pp

@@ -17263,7 +17263,7 @@ end;
 
 
 function TPasToJSConverter.CreateRTTIMemberProperty(Members: TFPList;
 function TPasToJSConverter.CreateRTTIMemberProperty(Members: TFPList;
   Index: integer; AContext: TConvertContext): TJSElement;
   Index: integer; AContext: TConvertContext): TJSElement;
-// create  $r.addProperty("propname",flags,result,"getter","setter",{options})
+// create  $r.addProperty("propname",flags,proptype,"getter","setter",{options})
 var
 var
   Prop: TPasProperty;
   Prop: TPasProperty;
   Call: TJSCallExpression;
   Call: TJSCallExpression;

+ 39 - 0
packages/pastojs/tests/tcmodules.pas

@@ -347,6 +347,7 @@ type
     Procedure TestAnonymousProc_Nested;
     Procedure TestAnonymousProc_Nested;
     Procedure TestAnonymousProc_NestedAssignResult;
     Procedure TestAnonymousProc_NestedAssignResult;
     Procedure TestAnonymousProc_Class;
     Procedure TestAnonymousProc_Class;
+    Procedure TestAnonymousProc_ForLoop;
 
 
     // enums, sets
     // enums, sets
     Procedure TestEnum_Name;
     Procedure TestEnum_Name;
@@ -4801,6 +4802,44 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestModule.TestAnonymousProc_ForLoop;
+begin
+  StartProgram(false);
+  Add([
+  'type TProc = reference to procedure;',
+  'procedure Foo(p: TProc);',
+  'begin',
+  'end;',
+  'procedure DoIt;',
+  'var i: word;',
+  '  a: word;',
+  'begin',
+  '  for i:=1 to 10 do begin',
+  '    Foo(procedure begin a:=3; end);',
+  '  end;',
+  'end;',
+  'begin',
+  '  DoIt;']);
+  ConvertProgram;
+  CheckSource('TestAnonymousProc_ForLoop',
+    LinesToStr([ // statements
+    'this.Foo = function (p) {',
+    '};',
+    'this.DoIt = function () {',
+    '  var i = 0;',
+    '  var a = 0;',
+    '  for (i = 1; i <= 10; i++) {',
+    '    $mod.Foo(function () {',
+    '      a = 3;',
+    '    });',
+    '  };',
+    '};',
+    '']),
+    LinesToStr([
+    '$mod.DoIt();'
+    ]));
+end;
+
 procedure TTestModule.TestEnum_Name;
 procedure TTestModule.TestEnum_Name;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 3 - 2
packages/paszlib/src/zipper.pp

@@ -2147,7 +2147,7 @@ Begin
   If Assigned(FOnCreateStream) then
   If Assigned(FOnCreateStream) then
     FOnCreateStream(Self, OutStream, Item);
     FOnCreateStream(Self, OutStream, Item);
   // If FOnCreateStream didn't create one, we create one now.
   // If FOnCreateStream didn't create one, we create one now.
-  If (OutStream=Nil) then
+  If (OutStream=Nil) and (not Item.IsDirectory) then
     begin
     begin
     if (Path<>'') then
     if (Path<>'') then
       ForceDirectories(Path);
       ForceDirectories(Path);
@@ -2173,7 +2173,8 @@ Begin
     OutStream := nil;
     OutStream := nil;
   end
   end
   else
   else
-    FreeAndNil(OutStream);
+    if Assigned(OutStream) then
+      FreeAndNil(OutStream);
   DoEndOfFile;
   DoEndOfFile;
 end;
 end;
 
 

+ 504 - 2
packages/rtl-objpas/src/i386/invoke.inc

@@ -440,11 +440,513 @@ begin
   end;
   end;
 end;
 end;
 
 
+const
+  PlaceholderContext = LongWord($12345678);
+  PlaceholderAddress = LongWord($87654321);
+  PlaceholderRetPop  = Word($1234);
+
+  RetNear = $C2;
+  RetFar = $CA;
+
+label
+  CallbackRegisterContext,
+  CallbackRegisterAddress,
+  CallbackRegisterCall,
+  CallbackRegisterRet,
+  CallbackRegisterEnd;
+
+const
+  CallbackRegisterContextPtr: Pointer = @CallbackRegisterContext;
+  CallbackRegisterAddressPtr: Pointer = @CallbackRegisterAddress;
+  CallbackRegisterCallPtr: Pointer = @CallbackRegisterCall;
+  CallbackRegisterRetPtr: Pointer = @CallbackRegisterRet;
+  CallbackRegisterEndPtr: Pointer = @CallbackRegisterEnd;
+
+procedure CallbackRegister; assembler; nostackframe;
+asm
+  { establish frame }
+  pushl %ebp
+  movl %esp, %ebp
+
+  { store registers }
+  pushl %ecx
+  pushl %edx
+  pushl %eax
+
+  { store pointer to stack area (including GP registers) }
+  lea (%esp), %edx
+
+  { also store ebx as we'll use that for the function address }
+  pushl %ebx
+
+  { call function with context }
+CallbackRegisterContext:
+  movl $0x12345678, %eax
+CallbackRegisterAddress:
+  movl $0x87654321, %ebx
+CallbackRegisterCall:
+
+  call *%ebx
+
+  { restore ebx }
+  popl %ebx
+
+  { restore stack }
+  movl %ebp, %esp
+  popl %ebp
+
+CallbackRegisterRet:
+  ret $0x1234
+CallbackRegisterEnd:
+end;
+
+type
+  TSystemFunctionCallback = class(TFunctionCallCallback)
+  private type
+    {$ScopedEnums On}
+    TArgType = (
+      GenReg,
+      Stack
+    );
+    {$ScopedEnums Off}
+
+    TArgInfo = record
+      ArgType: TArgType;
+      ArgIdx: SizeInt;
+      Slots: SizeInt;
+      Offset: SizeInt;
+      Deref: Boolean;
+    end;
+  private
+    fData: Pointer;
+    fSize: PtrUInt;
+    fFlags: TFunctionCallFlags;
+    fContext: Pointer;
+    fArgs: specialize TArray<TFunctionCallParameterInfo>;
+    fArgInfos: specialize TArray<TArgInfo>;
+    fRefArgs: specialize TArray<SizeInt>;
+    fResultType: PTypeInfo;
+    fResultIdx: SizeInt;
+    fResultInParam: Boolean;
+  private
+    function Handler(aStack: Pointer): Int64;
+  protected
+    procedure CreateCallback;
+    procedure CreateArgInfos;
+    function GetCodeAddress: CodePointer; override;
+    procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); virtual; abstract;
+  public
+    constructor Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+    destructor Destroy; override;
+  end;
+
+  TSystemFunctionCallbackMethod = class(TSystemFunctionCallback)
+  private
+    fHandler: TFunctionCallMethod;
+  protected
+    procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
+  public
+    constructor Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+  end;
+
+  TSystemFunctionCallbackProc = class(TSystemFunctionCallback)
+  private
+    fHandler: TFunctionCallProc;
+  protected
+    procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
+  public
+    constructor Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+  end;
+
+function TSystemFunctionCallback.Handler(aStack: Pointer): Int64;
+{
+  aStack has the following layout:
+    0:  EAX
+    4:  EDX
+    8:  ECX
+    12: EBP (not needed)
+    16: RET (not needed)
+    20: ARGS
+}
+var
+  args: specialize TArray<Pointer>;
+  i, len: SizeInt;
+  val: PPtrUInt;
+  resptr: Pointer;
+  genargs, stackargs: PPtrUInt;
+  floatres, floattmp: Extended;
+  td: PTypeData;
+begin
+  len := Length(fArgInfos);
+  if fResultInParam then
+    Dec(len);
+  SetLength(args, len);
+  genargs := PPtrUInt(aStack);
+  stackargs := @genargs[5];
+  for i := 0 to High(fArgInfos) do begin
+    if i = fResultIdx then
+      Continue;
+    case fArgInfos[i].ArgType of
+      TArgType.GenReg:
+        val := @genargs[fArgInfos[i].Offset];
+      TArgType.Stack:
+        val := @stackargs[fArgInfos[i].Offset];
+    end;
+    if fArgInfos[i].Deref then
+      args[fArgInfos[i].ArgIdx] := PPtrUInt(val^)
+    else
+      args[fArgInfos[i].ArgIdx] := val;
+  end;
+
+  if fResultInParam then begin
+    case fArgInfos[fResultIdx].ArgType of
+      TArgType.GenReg:
+        resptr := @genargs[fArgInfos[fResultIdx].Offset];
+      TArgType.Stack:
+        resptr := @stackargs[fArgInfos[fResultIdx].Offset];
+    end;
+    if fArgInfos[fResultIdx].Deref then
+      resptr := PPointer(resptr)^;
+  end else if Assigned(fResultType) then begin
+    if fResultType^.Kind = tkFloat then begin
+      resptr := @floatres;
+    end else
+      resptr := @Result;
+  end else
+    resptr := Nil;
+
+  CallHandler(args, resptr, fContext);
+
+  if Assigned(fResultType) and not fResultInParam and (fResultType^.Kind = tkFloat) then begin
+    td := GetTypeData(fResultType);
+    case td^.FloatType of
+      ftSingle:
+        asm
+          lea floatres, %eax
+          flds (%eax)
+          fwait
+        end ['eax'];
+      ftDouble:
+        asm
+          lea floatres, %eax
+          fldl (%eax)
+          fwait
+        end ['eax'];
+      ftExtended:
+        asm
+          lea floatres, %eax
+          fldt (%eax)
+          fwait
+        end ['eax'];
+      ftCurr,
+      ftComp:
+        asm
+          lea floatres, %eax
+          fildq (%eax)
+          fwait
+        end ['eax'];
+    end;
+  end;
+end;
+
+procedure TSystemFunctionCallback.CreateCallback;
+
+  procedure ReplacePlaceholder(aPlaceholder: PtrUInt; aValue: PtrUInt; aOfs, aSize: PtrUInt);
+  var
+    found: Boolean;
+    i: PtrUInt;
+  begin
+    found := False;
+    for i := aOfs to aOfs + aSize - 1 do begin
+      if PPtrUInt(@PByte(fData)[i])^ = PtrUInt(aPlaceholder) then begin
+        PPtrUInt(@(PByte(fData)[i]))^ := PtrUInt(aValue);
+        found := True;
+        Break;
+      end;
+    end;
+
+    if not found then
+      raise Exception.Create(SErrMethodImplCreateFailed);
+  end;
+
+var
+  src: Pointer;
+  ofs, size: PtrUInt;
+  method: TMethod;
+  i, stacksize: SizeInt;
+begin
+  fSize := PtrUInt(CallbackRegisterEndPtr) - PtrUInt(@CallbackRegister) + 1;
+  fData := AllocateMemory(fSize);
+  if not Assigned(fData) then
+    raise Exception.Create(SErrMethodImplCreateFailed);
+
+  src := @CallbackRegister;
+  Move(src^, fData^, fSize);
+
+  ofs := PtrUInt(CallbackRegisterContextPtr) - PtrUInt(@CallbackRegister);
+  size := PtrUInt(CallbackRegisterAddressPtr) - PtrUInt(CallbackRegisterContextPtr);
+
+  method := TMethod(@Handler);
+
+  ReplacePlaceholder(PlaceholderContext, PtrUInt(method.Data), ofs, size);
+
+  ofs := PtrUInt(CallbackRegisterAddressPtr) - PtrUInt(@CallbackRegister);
+  size := PtrUInt(CallbackRegisterCallPtr) - PtrUInt(CallbackRegisterAddressPtr);
+
+  ReplacePlaceholder(PlaceholderAddress, PtrUInt(method.Code), ofs, size);
+
+  ofs := PtrUInt(CallbackRegisterRetPtr) - PtrUInt(@CallbackRegister);
+  size := PtrUInt(CallbackRegisterEndPtr) - PtrUInt(CallbackRegisterRetPtr);
+
+  if not (PByte(fData)[ofs] = RetNear) and not (PByte(fData)[ofs] = RetFar) then
+    raise Exception.Create(SErrMethodImplCreateFailed);
+
+  stacksize := 0;
+  for i := 0 to High(fArgInfos) do
+    if fArgInfos[i].ArgType = TArgType.Stack then
+      Inc(stacksize, fArgInfos[i].Slots);
+
+  stacksize := stacksize * 4;
+
+  Inc(ofs);
+  if PWord(@PByte(fData)[ofs])^ = PlaceholderRetPop then
+    PWord(@PByte(fData)[ofs])^ := Word(stacksize);
+
+  if not ProtectMemory(fData, fSize, True) then
+    raise Exception.Create(SErrMethodImplCreateFailed);
+end;
+
+procedure TSystemFunctionCallback.CreateArgInfos;
+var
+  pass, genofs, stackofs: LongInt;
+  td: PTypeData;
+  i, c, argcount, stackcount, idx, argidx: SizeInt;
+  stackargs: array of SizeInt;
+begin
+  fResultInParam := ReturnResultInParam(fResultType);
+
+  genofs := 0;
+  stackofs := 0;
+  argidx := 0;
+  argcount := Length(fArgs);
+  if fResultInParam then begin
+    if fcfStatic in fFlags then
+      fResultIdx := 0
+    else
+      fResultIdx := 1;
+    Inc(argcount);
+  end else
+    fResultIdx := -1;
+  SetLength(fArgInfos, argcount);
+  SetLength(fRefArgs, argcount);
+  if fResultIdx >= 0 then begin
+    fArgInfos[fResultIdx].ArgType := TArgType.GenReg;
+    fArgInfos[fResultIdx].Offset := fResultIdx;
+  end;
+
+  SetLength(stackargs, argcount);
+  stackcount := 0;
+
+  for pass := 0 to 1 do begin
+    if pass = 0 then
+      c := High(fArgs)
+    else
+      c := stackcount - 1;
+    for i := 0 to c do begin
+      if argidx = fResultIdx then
+        Inc(argidx);
+      if pfResult in fArgs[i].ParamFlags then begin
+        fResultIdx := argidx;
+        fResultInParam := True;
+      end;
+      if (pass = 0) and (genofs >= 3) then begin
+        stackargs[stackcount] := i;
+        Inc(stackcount);
+        Continue;
+      end;
+      if pass = 0 then
+        idx := i
+      else
+        idx := stackargs[c - i];
+      if pass = 0 then
+        fArgInfos[argidx].ArgType := TArgType.GenReg
+      else
+        fArgInfos[argidx].ArgType := TArgType.Stack;
+      fArgInfos[argidx].Deref := False;
+      fArgInfos[argidx].Slots := 1;
+      if pfArray in fArgs[idx].ParamFlags then
+        fArgInfos[argidx].Deref := True
+      else if fArgs[idx].ParamFlags * [pfOut, pfVar, pfConstRef] <> [] then
+        fArgInfos[argidx].Deref := True
+      else if (pfConst in fArgs[idx].ParamFlags) and not Assigned(fArgs[idx].ParamType) then
+        fArgInfos[argidx].Deref := True
+      else begin
+        td := GetTypeData(fArgs[idx].ParamType);
+        case fArgs[idx].ParamType^.Kind of
+          tkSString,
+          tkMethod:
+            fArgInfos[argidx].Deref := True;
+          tkArray:
+            if td^.ArrayData.Size <= 4 then begin
+              fArgInfos[argidx].Deref := True;
+              fArgInfos[argidx].ArgType := TArgType.Stack;
+            end;
+          tkRecord:
+            if td^.RecSize <= 4 then begin
+              fArgInfos[argidx].Deref := True;
+              fArgInfos[argidx].ArgType := TArgType.Stack;
+            end;
+          tkObject,
+          tkWString,
+          tkUString,
+          tkAString,
+          tkDynArray,
+          tkClass,
+          tkClassRef,
+          tkInterface,
+          tkInterfaceRaw,
+          tkProcVar,
+          tkPointer:
+            ;
+          tkInt64,
+          tkQWord: begin
+            fArgInfos[argidx].ArgType := TArgType.Stack;
+            fArgInfos[argidx].Slots := 2;
+          end;
+          tkSet: begin
+            case td^.OrdType of
+              otUByte: begin
+                case td^.SetSize of
+                  0, 1, 2, 4:
+                    ;
+                  else
+                    fArgInfos[argidx].Deref := True;
+                end;
+              end;
+              otUWord,
+              otULong:
+                ;
+            end;
+          end;
+          tkEnumeration,
+          tkInteger:
+            ;
+          tkBool:
+            case td^.OrdType of
+              otUQWord,
+              otSQWord:
+                fArgInfos[argidx].ArgType := TArgType.Stack;
+            end;
+          tkFloat: begin
+            fArgInfos[argidx].ArgType := TArgType.Stack;
+            case td^.FloatType of
+              ftSingle:
+                ;
+              ftCurr,
+              ftComp,
+              ftDouble:
+                fArgInfos[argidx].Slots := 2;
+              ftExtended:
+                fArgInfos[argidx].Slots := 3;
+            end;
+          end;
+        else
+          raise EInvocationError.CreateFmt(SErrFailedToConvertArg, [idx, fArgs[idx].ParamType^.Name]);
+        end;
+      end;
+
+      { ignore stack arguments in first pass }
+      if (pass = 0) and (fArgInfos[argidx].ArgType = TArgType.Stack) then begin
+        stackargs[stackcount] := idx;
+        Inc(stackcount);
+        Continue;
+      end;
+
+      if fArgInfos[argidx].ArgType = TArgType.GenReg then begin
+        fArgInfos[argidx].ArgIdx := idx;
+        fArgInfos[argidx].Offset := genofs;
+        Inc(genofs);
+      end else if fArgInfos[argidx].ArgType = TArgType.Stack then begin
+        fArgInfos[argidx].ArgIdx := idx;
+        fArgInfos[argidx].Offset := stackofs;
+        Inc(stackofs, fArgInfos[argidx].Slots);
+      end;
+
+      Inc(argidx);
+    end;
+  end;
+end;
+
+function TSystemFunctionCallback.GetCodeAddress: CodePointer;
+begin
+  Result := fData;
+end;
+
+constructor TSystemFunctionCallback.Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+
+  function CallConvName: String; inline;
+  begin
+    WriteStr(Result, aCallConv);
+  end;
+
+var
+  i: SizeInt;
+begin
+  if not (aCallConv in [ccReg]) then
+    raise ENotImplemented.CreateFmt(SErrCallConvNotSupported, [CallConvName]);
+  fContext := aContext;
+  SetLength(fArgs, Length(aArgs));
+  for i := 0 to High(aArgs) do
+    fArgs[i] := aArgs[i];
+  fResultType := aResultType;
+  fFlags := aFlags;
+  CreateArgInfos;
+  CreateCallback;
+end;
+
+destructor TSystemFunctionCallback.Destroy;
+begin
+  if Assigned(fData) then
+    FreeMemory(fData, fSize);
+end;
+
+constructor TSystemFunctionCallbackProc.Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+begin
+  inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
+  fHandler := aHandler;
+end;
+
+procedure TSystemFunctionCallbackProc.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
+begin
+  fHandler(aArgs, aResult, aContext);
+end;
+
+constructor TSystemFunctionCallbackMethod.Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
+begin
+  inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
+  fHandler := aHandler;
+end;
+
+procedure TSystemFunctionCallbackMethod.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
+begin
+  fHandler(aArgs, aResult, aContext);
+end;
+
+function SystemCreateCallbackProc(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
+begin
+  Result := TSystemFunctionCallbackProc.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
+end;
+
+function SystemCreateCallbackMethod(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
+begin
+  Result := TSystemFunctionCallbackMethod.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
+end;
+
 const
 const
   SystemFunctionCallManager: TFunctionCallManager = (
   SystemFunctionCallManager: TFunctionCallManager = (
     Invoke: @SystemInvoke;
     Invoke: @SystemInvoke;
-    CreateCallbackProc: Nil;
-    CreateCallbackMethod: Nil;
+    CreateCallbackProc: @SystemCreateCallbackProc;
+    CreateCallbackMethod: @SystemCreateCallbackMethod;
   );
   );
 
 
 procedure InitSystemFunctionCallManager;
 procedure InitSystemFunctionCallManager;

+ 16 - 4
packages/rtl-objpas/src/inc/rtti.pp

@@ -576,6 +576,9 @@ implementation
 uses
 uses
 {$ifdef windows}
 {$ifdef windows}
   Windows,
   Windows,
+{$endif}
+{$ifdef unix}
+  BaseUnix,
 {$endif}
 {$endif}
   fgl;
   fgl;
 
 
@@ -749,8 +752,10 @@ function AllocateMemory(aSize: PtrUInt): Pointer;
 begin
 begin
 {$IF DEFINED(WINDOWS)}
 {$IF DEFINED(WINDOWS)}
   Result := VirtualAlloc(Nil, aSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
   Result := VirtualAlloc(Nil, aSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
+{$ELSEIF DEFINED(UNIX)}
+  Result := fpmmap(Nil, aSize, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, 0, 0);
 {$ELSE}
 {$ELSE}
-  Result := GetMem(aSize);
+  Result := Nil;
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 
@@ -765,17 +770,24 @@ begin
     Result := VirtualProtect(aPtr, aSize, PAGE_EXECUTE_READ, oldprot)
     Result := VirtualProtect(aPtr, aSize, PAGE_EXECUTE_READ, oldprot)
   else
   else
     Result := VirtualProtect(aPtr, aSize, PAGE_READWRITE, oldprot);
     Result := VirtualProtect(aPtr, aSize, PAGE_READWRITE, oldprot);
+{$ELSEIF DEFINED(UNIX)}
+  if aExecutable then
+    Result := Fpmprotect(aPtr, aSize, PROT_EXEC or PROT_READ) = 0
+  else
+    Result := Fpmprotect(aPtr, aSize, PROT_READ or PROT_WRITE) = 0;
 {$ELSE}
 {$ELSE}
-  Result := True;
+  Result := False;
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 
-procedure FreeMemory(aPtr: Pointer);
+procedure FreeMemory(aPtr: Pointer; aSize: PtrUInt);
 begin
 begin
 {$IF DEFINED(WINDOWS)}
 {$IF DEFINED(WINDOWS)}
   VirtualFree(aPtr, 0, MEM_RELEASE);
   VirtualFree(aPtr, 0, MEM_RELEASE);
+{$ELSEIF DEFINED(UNIX)}
+  fpmunmap(aPtr, aSize);
 {$ELSE}
 {$ELSE}
-  FreeMem(aPtr);
+  { nothing }
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 

+ 1 - 1
packages/rtl-objpas/src/x86_64/invoke.inc

@@ -654,7 +654,7 @@ destructor TSystemFunctionCallback.Destroy;
 begin
 begin
 {$ifdef windows}
 {$ifdef windows}
   if Assigned(fData) then
   if Assigned(fData) then
-    FreeMemory(fData);
+    FreeMemory(fData, fSize);
 {$endif}
 {$endif}
 end;
 end;
 
 

+ 1 - 0
packages/rtl-objpas/tests/testrunner.rtlobjpas.pp

@@ -11,6 +11,7 @@ program testrunner.rtlobjpas;
 {$define testimpl}
 {$define testimpl}
 {$elseif defined(CPUI386)}
 {$elseif defined(CPUI386)}
 {$define testinvoke}
 {$define testinvoke}
+{$define testimpl}
 {$else}
 {$else}
 {$ifdef useffi}
 {$ifdef useffi}
 {$define testinvoke}
 {$define testinvoke}

+ 18 - 3
packages/rtl-objpas/tests/tests.rtti.impl.pas

@@ -426,7 +426,12 @@ begin
         InputUntypedTypes[i + 1] := Nil;
         InputUntypedTypes[i + 1] := Nil;
     end;
     end;
 
 
-    impl := method.CreateImplementation({$ifdef fpc}@{$endif}OnHandleInvokable);
+    try
+      impl := method.CreateImplementation({$ifdef fpc}@{$endif}OnHandleInvokable);
+    except
+      on e: ENotImplemented do
+        Exit;
+    end;
     CheckNotNull(impl, 'Method implementation is Nil');
     CheckNotNull(impl, 'Method implementation is Nil');
 
 
     mrec.Data := Self;
     mrec.Data := Self;
@@ -501,7 +506,12 @@ begin
         InputUntypedTypes[i] := Nil;
         InputUntypedTypes[i] := Nil;
     end;
     end;
 
 
-    impl := proc.CreateImplementation({$ifdef fpc}@{$endif}OnHandleInvokable);
+    try
+      impl := proc.CreateImplementation({$ifdef fpc}@{$endif}OnHandleInvokable);
+    except
+      on e: ENotImplemented do
+        Exit;
+    end;
     CheckNotNull(impl, 'Method implementation is Nil');
     CheckNotNull(impl, 'Method implementation is Nil');
 
 
     cp := impl.CodeAddress;
     cp := impl.CodeAddress;
@@ -555,7 +565,12 @@ procedure TTestImpl.TestIntfMethods;
 var
 var
   intf: ITestInterface;
   intf: ITestInterface;
 begin
 begin
-  intf := TVirtualInterface.Create(PTypeInfo(TypeInfo(ITestInterface)), {$ifdef fpc}@{$endif}OnHandleIntfMethod) as ITestInterface;
+  try
+    intf := TVirtualInterface.Create(PTypeInfo(TypeInfo(ITestInterface)), {$ifdef fpc}@{$endif}OnHandleIntfMethod) as ITestInterface;
+  except
+    on e: ENotImplemented do
+      Exit;
+  end;
   Check(Assigned(intf), 'ITestInterface instance is Nil');
   Check(Assigned(intf), 'ITestInterface instance is Nil');
 
 
   {$ifdef fpc}specialize{$endif}GenDoIntfImpl<ITestInterface>(intf, 1, [], [], [], TValue.Empty);
   {$ifdef fpc}specialize{$endif}GenDoIntfImpl<ITestInterface>(intf, 1, [], [], [], TValue.Empty);

+ 1 - 1
packages/winunits-base/src/imm.pas

@@ -434,7 +434,7 @@ function ImmGetStatusWindowPos(imc: HIMC; lpptPos: LPPOINT): LongBool; stdcall ;
 function ImmSetStatusWindowPos(imc: HIMC; lpptPos: LPPOINT): LongBool; stdcall ; external Imm name 'ImmSetStatusWindowPos';
 function ImmSetStatusWindowPos(imc: HIMC; lpptPos: LPPOINT): LongBool; stdcall ; external Imm name 'ImmSetStatusWindowPos';
 function ImmGetCompositionWindow(imc: HIMC; lpCompForm: LPCOMPOSITIONFORM): LongBool; stdcall ; external Imm name 'ImmGetCompositionWindow';
 function ImmGetCompositionWindow(imc: HIMC; lpCompForm: LPCOMPOSITIONFORM): LongBool; stdcall ; external Imm name 'ImmGetCompositionWindow';
 function ImmSetCompositionWindow(imc: HIMC; lpCompForm: LPCOMPOSITIONFORM): LongBool; stdcall ; external Imm name 'ImmSetCompositionWindow';
 function ImmSetCompositionWindow(imc: HIMC; lpCompForm: LPCOMPOSITIONFORM): LongBool; stdcall ; external Imm name 'ImmSetCompositionWindow';
-function ImmGetCandidateWindow(imc: HIMC; par1: DWORD; lpCandidate: LPCANDIDATEFORM): LongBool; stdcall ; external Imm name 'ImmGetCandidateWindow(';
+function ImmGetCandidateWindow(imc: HIMC; par1: DWORD; lpCandidate: LPCANDIDATEFORM): LongBool; stdcall ; external Imm name 'ImmGetCandidateWindow';
 function ImmSetCandidateWindow(imc: HIMC; lpCandidate: LPCANDIDATEFORM): LongBool; stdcall ; external Imm name 'ImmSetCandidateWindow';
 function ImmSetCandidateWindow(imc: HIMC; lpCandidate: LPCANDIDATEFORM): LongBool; stdcall ; external Imm name 'ImmSetCandidateWindow';
 
 
 function ImmIsUIMessageA(wnd: HWND; msg: UINT; wPar: WPARAM; lPar: LPARAM): LongBool; stdcall ; external Imm name 'ImmIsUIMessageA';
 function ImmIsUIMessageA(wnd: HWND; msg: UINT; wPar: WPARAM; lPar: LPARAM): LongBool; stdcall ; external Imm name 'ImmIsUIMessageA';

+ 963 - 4
packages/winunits-base/src/shlwapi.pp

@@ -2,8 +2,8 @@ unit shlwapi;
 
 
 {
 {
     This file is part of the Free Pascal run time library.
     This file is part of the Free Pascal run time library.
-    shlwapi calls are parked here for now.
-    Copyright (c) 1999-2002 by Marco van de Voort,
+    partial shlwapi.h header translation
+    Copyright (c) 1999-2019 by Marco van de Voort,
     member of the Free Pascal development team.
     member of the Free Pascal development team.
 
 
     See the file COPYING.FPC, included in this distribution,
     See the file COPYING.FPC, included in this distribution,
@@ -18,8 +18,967 @@ unit shlwapi;
 interface
 interface
 {$mode delphi}
 {$mode delphi}
 
 
-function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; stdcall; external 'shlwapi.dll';
+Uses Windows,ActiveX;
+  const
+    SHLWAPIDLL='shlwapi.dll'; {Setup as you need}
+
+Type
+  SFBS_FLAGS = longint;
+  STIF_FLAGS = longint;
+  SRRF       = integer;
+  LSTATUS    = LONG;
+  HUSKEY     = THANDLE;
+  PHUSKEY    = PHANDLE;
+  SHCT_FLAGS = DWORD;   // SHCreateThread flags values
+  ASSOCF     = DWORD;
+  PHWND      = PHANDLE;
+  PPIDLIST_RELATIVE  = PITEMIDLIST;
+  PCUIDLIST_RELATIVE = PITEMIDLIST;
+  PCIDLIST_ABSOLUTE  = PITEMIDLIST;
+
+  PPERCEIVEDFLAG     = ^PERCEIVEDFLAG;
+  PERCEIVEDFLAG      = DWORD;
+
+  PSFBS_FLAGS  = ^SFBS_FLAGS;
+  PSTIF_FLAGS  = ^STIF_FLAGS;
+  PtagSFBS_FLAGS  = ^tagSFBS_FLAGS;
+    tagSFBS_FLAGS = (SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT = $0001,
+      SFBS_FLAGS_TRUNCATE_UNDISPLAYED_DECIMAL_DIGITS = $0002
+      );
+  PCUITEMID_CHILD= PITEMIDLIST;
+  PZPCSTR = PLPSTR;   // PLPCSTR
+  PZPCWSTR = PLPWSTR; // PLPCWSTR
+
+const
+  STIF_DEFAULT     = $00000000;
+  STIF_SUPPORT_HEX = $00000001;
+
+Type
+  PURL_SCHEME = ^URL_SCHEME;
+  URL_SCHEME = (
+      URL_SCHEME_INVALID = -(1),
+      URL_SCHEME_UNKNOWN = 0,
+      URL_SCHEME_FTP,
+      URL_SCHEME_HTTP,
+      URL_SCHEME_GOPHER,
+      URL_SCHEME_MAILTO,
+      URL_SCHEME_NEWS,
+      URL_SCHEME_NNTP,
+      URL_SCHEME_TELNET,
+      URL_SCHEME_WAIS,
+      URL_SCHEME_FILE,
+      URL_SCHEME_MK,
+      URL_SCHEME_HTTPS,
+      URL_SCHEME_SHELL,
+      URL_SCHEME_SNEWS,
+      URL_SCHEME_LOCAL,
+      URL_SCHEME_JAVASCRIPT,
+      URL_SCHEME_VBSCRIPT,
+      URL_SCHEME_ABOUT,
+      URL_SCHEME_RES,
+      URL_SCHEME_MSSHELLROOTED,
+      URL_SCHEME_MSSHELLIDLIST,
+      URL_SCHEME_MSHELP,
+      URL_SCHEME_MSSHELLDEVICE,
+      URL_SCHEME_WILDCARD,
+      URL_SCHEME_SEARCH_MS,
+      URL_SCHEME_SEARCH,
+      URL_SCHEME_KNOWNFOLDER,
+      URL_SCHEME_MAXVALUE
+      );
+
+  PURL_PART = ^URL_PART;
+  URL_PART = (
+      URL_PART_NONE = 0,
+      URL_PART_SCHEME = 1,
+      URL_PART_HOSTNAME,
+      URL_PART_USERNAME,
+      URL_PART_PASSWORD,
+      URL_PART_PORT,
+      URL_PART_QUERY);
+
+  PURLIS = ^URLIS;
+  URLIS = (
+      URLIS_URL =0,
+      URLIS_OPAQUE,
+      URLIS_NOHISTORY,
+      URLIS_FILEURL,
+      URLIS_APPLIABLE,
+      URLIS_DIRECTORY,
+      URLIS_HASQUERY);
+
+
+  SHREGDEL_FLAGS = (
+    SHREGDEL_DEFAULT = $00000000,       // Delete's HKCU, or HKLM if HKCU is not found.
+    SHREGDEL_HKCU    = $00000001,       // Delete HKCU only
+    SHREGDEL_HKLM    = $00000010,       // Delete HKLM only.
+    SHREGDEL_BOTH    = $00000011        // Delete both HKCU and HKLM.
+   );
+
+
+  SHREGENUM_FLAGS = (
+    SHREGENUM_DEFAULT = $00000000,       // Enumerates HKCU or HKLM if not found.
+    SHREGENUM_HKCU    = $00000001,       // Enumerates HKCU only
+    SHREGENUM_HKLM    = $00000010,       // Enumerates HKLM only.
+    SHREGENUM_BOTH    = $00000011        // Enumerates both HKCU and HKLM without duplicates.
+   );                                       // This option is NYI.
+  ASSOCSTR = (
+      ASSOCSTR_COMMAND      = 1,  //  shell\verb\command string
+      ASSOCSTR_EXECUTABLE,        //  the executable part of command string
+      ASSOCSTR_FRIENDLYDOCNAME,   //  friendly name of the document type
+      ASSOCSTR_FRIENDLYAPPNAME,   //  friendly name of executable
+      ASSOCSTR_NOOPEN,            //  noopen value
+      ASSOCSTR_SHELLNEWVALUE,     //  query values under the shellnew key
+      ASSOCSTR_DDECOMMAND,        //  template for DDE commands
+      ASSOCSTR_DDEIFEXEC,         //  DDECOMMAND to use if just create a process
+      ASSOCSTR_DDEAPPLICATION,    //  Application name in DDE broadcast
+      ASSOCSTR_DDETOPIC,          //  Topic Name in DDE broadcast
+      ASSOCSTR_INFOTIP,           //  info tip for an item, or list of properties to create info tip from
+  //#if (_WIN32_IE >= _WIN32_IE_IE60)
+      ASSOCSTR_QUICKTIP,          //  same as ASSOCSTR_INFOTIP, except, this list contains only quickly retrievable properties
+      ASSOCSTR_TILEINFO,          //  similar to ASSOCSTR_INFOTIP - lists important properties for tileview
+      ASSOCSTR_CONTENTTYPE,       //  MIME Content type
+      ASSOCSTR_DEFAULTICON,       //  Default icon source
+      ASSOCSTR_SHELLEXTENSION,    //  Guid string pointing to the Shellex\Shellextensionhandler value.
+  //#endif // _WIN32_IE_IE60
+
+      ASSOCSTR_DROPTARGET,        //  The CLSID of DropTarget   IE8+
+      ASSOCSTR_DELEGATEEXECUTE,   //  The CLSID of DelegateExecute IE8+
+
+      // a string value of the uri protocol schemes, for example "http:https:ftp:file:" or "*" indicating all
+      ASSOCSTR_SUPPORTED_URI_PROTOCOLS,
+  //#if (NTDDI_VERSION >= NTDDI_WIN10)
+      ASSOCSTR_PROGID,            // The ProgId provided by the app associated with the file type or uri scheme based on user default settings.
+      ASSOCSTR_APPID,             // The AppUserModelID of the app associated with the file type or uri scheme based on user default settings.
+      ASSOCSTR_APPPUBLISHER,      // THe publisher of the app associated with the file type or uri scheme based on user default settings.
+      ASSOCSTR_APPICONREFERENCE,  // The icon reference of the app associated with the file type or uri scheme based on user default settings.
+  //#endif // NTDDI_WIN10
+      ASSOCSTR_MAX                //  last item in enum...
+  );
+
+
+  ASSOCKEY = (
+      ASSOCKEY_SHELLEXECCLASS = 1,  //  the key that should be passed to ShellExec(hkeyClass)
+      ASSOCKEY_APP,                 //  the "Application" key for the association
+      ASSOCKEY_CLASS,               //  the progid or class key
+      ASSOCKEY_BASECLASS,           //  the BaseClass key
+      ASSOCKEY_MAX                  //  last item in enum...
+   );
+
+  ASSOCDATA = (
+      ASSOCDATA_MSIDESCRIPTOR = 1,  //  Component Descriptor to pass to MSI APIs
+      ASSOCDATA_NOACTIVATEHANDLER,  //  restrict attempts to activate window
+      ASSOCDATA_UNUSED1,            //  removed QUERYCLASSSTORE, dead code
+      ASSOCDATA_HASPERUSERASSOC,    //  defaults to user specified association
+      ASSOCDATA_EDITFLAGS,          //  Edit flags. IE6+
+      ASSOCDATA_VALUE,              //  use pszExtra as the Value name IE6+
+      ASSOCDATA_MAX
+  );
+
+  ASSOCENUM = (
+      ASSOCENUM_NONE = 1
+  );
+
+
+ SHGLOBALCOUNTER = (
+    GLOBALCOUNTER_SEARCHMANAGER =0,
+    GLOBALCOUNTER_SEARCHOPTIONS,
+    GLOBALCOUNTER_FOLDERSETTINGSCHANGE,
+    GLOBALCOUNTER_RATINGS,
+    GLOBALCOUNTER_APPROVEDSITES,
+    GLOBALCOUNTER_RESTRICTIONS,
+    GLOBALCOUNTER_SHELLSETTINGSCHANGED,
+    GLOBALCOUNTER_SYSTEMPIDLCHANGE,
+    GLOBALCOUNTER_OVERLAYMANAGER,
+    GLOBALCOUNTER_QUERYASSOCIATIONS,
+    GLOBALCOUNTER_IESESSIONS,
+    GLOBALCOUNTER_IEONLY_SESSIONS,
+    GLOBALCOUNTER_APPLICATION_DESTINATIONS,
+    __UNUSED_RECYCLE_WAS_GLOBALCOUNTER_CSCSYNCINPROGRESS,
+    GLOBALCOUNTER_BITBUCKETNUMDELETERS,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_SHARES,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_A,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_B,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_C,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_D,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_E,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_F,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_G,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_H,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_I,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_J,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_K,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_L,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_M,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_N,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_O,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_P,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_Q,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_R,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_S,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_T,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_U,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_V,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_W,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_X,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_Y,
+    GLOBALCOUNTER_RECYCLEDIRTYCOUNT_DRIVE_Z,
+    __UNUSED_RECYCLE_WAS_GLOBALCOUNTER_RECYCLEDIRTYCOUNT_SERVERDRIVE,
+    __UNUSED_RECYCLE_WAS_GLOBALCOUNTER_RECYCLEGLOBALDIRTYCOUNT,
+    GLOBALCOUNTER_RECYCLEBINENUM,
+    GLOBALCOUNTER_RECYCLEBINCORRUPTED,
+    GLOBALCOUNTER_RATINGS_STATECOUNTER,
+    GLOBALCOUNTER_PRIVATE_PROFILE_CACHE,
+    GLOBALCOUNTER_INTERNETTOOLBAR_LAYOUT,
+    GLOBALCOUNTER_FOLDERDEFINITION_CACHE,
+    GLOBALCOUNTER_COMMONPLACES_LIST_CACHE,
+    GLOBALCOUNTER_PRIVATE_PROFILE_CACHE_MACHINEWIDE,
+    GLOBALCOUNTER_ASSOCCHANGED,  // throttles reading of the registry value "GlobalAssocChangedCounter" from HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer
+//#if (NTDDI_VERSION >= NTDDI_WIN8)
+    GLOBALCOUNTER_APP_ITEMS_STATE_STORE_CACHE,
+    GLOBALCOUNTER_SETTINGSYNC_ENABLED,
+    GLOBALCOUNTER_APPSFOLDER_FILETYPEASSOCIATION_COUNTER,
+    GLOBALCOUNTER_USERINFOCHANGED,
+    GLOBALCOUNTER_SYNC_ENGINE_INFORMATION_CACHE_MACHINEWIDE, // WINBLUE+
+//#endif // (NTDDI_VERSION >= NTDDI_WIN8)
+    GLOBALCOUNTER_BANNERS_DATAMODEL_CACHE_MACHINEWIDE, // WIN10_RS1+
+
+    GLOBALCOUNTER_MAXIMUMVALUE // should always be last value
+  );
+
+
+  // Stored under HKCR\<progId> EditFlags(REG_DWORD)
+  //
+  // Retrieve these values using IQueryAssociations::GetData as follows
+  //
+  // DWORD editFlags, size = sizeof(editFlags);
+  // queryAssoc->GetData(nullptr, ASSOCDATA_EDITFLAGS, nullptr, &editFlags, &size);
+  //
+  // Some of these flags are no longer used since editing file type associations has been
+  // removed from Explorer's folder options UI.
+
+
+  FILETYPEATTRIBUTEFLAGS = (
+      FTA_None                    = $00000000,
+      FTA_Exclude                 = $00000001, // used to exclude (hide) types like drvfile
+      FTA_Show                    = $00000002, // used to show types like folder that don't have associations
+      FTA_HasExtension            = $00000004, // type has a file name extension
+      FTA_NoEdit                  = $00000008, // no editing of file type
+      FTA_NoRemove                = $00000010, // no removing of the file type
+      FTA_NoNewVerb               = $00000020, // no adding of verbs
+      FTA_NoEditVerb              = $00000040, // no editing of predefined verbs
+      FTA_NoRemoveVerb            = $00000080, // no removing of predefined verbs
+      FTA_NoEditDesc              = $00000100, // no editing of file type description
+      FTA_NoEditIcon              = $00000200, // no editing of doc icon
+      FTA_NoEditDflt              = $00000400, // no changing of default verb
+      FTA_NoEditVerbCmd           = $00000800, // no modification of the commnds associated with the verbs
+      FTA_NoEditVerbExe           = $00001000, // no editing of the verb's exe
+      FTA_NoDDE                   = $00002000, // no editing of the DDE fields
+
+      FTA_NoEditMIME              = $00008000, // no editing of the Content Type or Default Extension fields
+      FTA_OpenIsSafe              = $00010000, // the open verb should be invoked automaticaly for downloaded files
+      FTA_AlwaysUnsafe            = $00020000, // don't allow the "Never ask me" checkbox to be enabled; File Type dialog still allows user to turn this off
+
+      FTA_NoRecentDocs            = $00100000, // don't add this file type to the Recent Documents folder
+      FTA_SafeForElevation        = $00200000, // Win8: can be launched in medium IL by a process running in AppContainer
+      FTA_AlwaysUseDirectInvoke   = $00400000 // Win8: when downloading use the direct invoke feature even if the server headers are not provided
+   );
+  PPERCEIVED  = ^PERCEIVED;
+  PERCEIVED = (
+       PERCEIVED_TYPE_CUSTOM    = -3,
+       PERCEIVED_TYPE_UNSPECIFIED       = -2,
+       PERCEIVED_TYPE_FOLDER    = -1,
+       PERCEIVED_TYPE_UNKNOWN   = 0,
+       PERCEIVED_TYPE_TEXT      = 1,
+       PERCEIVED_TYPE_IMAGE     = 2,
+       PERCEIVED_TYPE_AUDIO     = 3,
+       PERCEIVED_TYPE_VIDEO     = 4,
+       PERCEIVED_TYPE_COMPRESSED        = 5,
+       PERCEIVED_TYPE_DOCUMENT  = 6,
+       PERCEIVED_TYPE_SYSTEM    = 7,
+       PERCEIVED_TYPE_APPLICATION       = 8,
+       PERCEIVED_TYPE_GAMEMEDIA = 9,
+       PERCEIVED_TYPE_CONTACTS  = 10
+       );
+
+const
+      PERCEIVED_TYPE_LAST      = PERCEIVED_TYPE_CONTACTS;
+      PERCEIVED_TYPE_FIRST     = PERCEIVED_TYPE_CUSTOM;
+
+type
+
+
+
+  PtagPARSEDURLA = ^tagPARSEDURLA;
+    tagPARSEDURLA = record
+        cbSize : DWORD;
+        pszProtocol : LPCSTR;
+        cchProtocol : UINT;
+        pszSuffix : LPCSTR;
+        cchSuffix : UINT;
+        nScheme : UINT;
+      end;
+    PARSEDURLA = tagPARSEDURLA;
+    PPARSEDURLA = ^PARSEDURLA;
+    PPPARSEDURLA = ^PPARSEDURLA;
+    PtagPARSEDURLW = ^tagPARSEDURLW;
+    tagPARSEDURLW = record
+        cbSize : DWORD;
+        pszProtocol : LPCWSTR;
+        cchProtocol : UINT;
+        pszSuffix : LPCWSTR;
+        cchSuffix : UINT;
+        nScheme : UINT;
+      end;
+    PARSEDURLW = tagPARSEDURLW;
+    PPARSEDURLW = ^PARSEDURLW;
+    PPPARSEDURLW = ^PPARSEDURLW;
+{$ifdef UNICODE}
+    PARSEDURL = PARSEDURLW;
+    PPPARSEDURL = ^PPARSEDURL;
+    PPARSEDURL = PPARSEDURLW;
+{$else}
+    PARSEDURL = PARSEDURLA;
+    PPPARSEDURL = ^PPARSEDURL;
+    PPARSEDURL = PPARSEDURLA;
+{$endif}
+
+const
+
+    URL_UNESCAPE               = $10000000;
+    URL_ESCAPE_UNSAFE          = $20000000;
+    URL_PLUGGABLE_PROTOCOL     = $40000000;
+    URL_WININET_COMPATIBILITY  = $80000000;
+    URL_DONT_ESCAPE_EXTRA_INFO = $02000000;
+    URL_DONT_UNESCAPE_EXTRA_INFO = URL_DONT_ESCAPE_EXTRA_INFO;
+    URL_BROWSER_MODE           = URL_DONT_ESCAPE_EXTRA_INFO;
+    URL_ESCAPE_SPACES_ONLY     = $04000000;
+    URL_DONT_SIMPLIFY          = $08000000;
+    URL_NO_META = URL_DONT_SIMPLIFY;
+    URL_UNESCAPE_INPLACE       = $00100000;
+    URL_CONVERT_IF_DOSPATH     = $00200000;
+    URL_UNESCAPE_HIGH_ANSI_ONLY= $00400000;
+    URL_INTERNAL_PATH          = $00800000;    { Will escape #'s in paths }
+    URL_FILE_USE_PATHURL       = $00010000;
+    URL_DONT_UNESCAPE          = $00020000;    { Do not unescape the path/url at all IE6.0SP2++ }
+    URL_ESCAPE_AS_UTF8         = $00040000;    { Percent-encode all non-ASCII characters as their UTF-8 equivalents. Win7+ }
+  {#if (NTDDI_VERSION >= NTDDI_WIN8) }
+    URL_UNESCAPE_AS_UTF8       = URL_ESCAPE_AS_UTF8;
+    URL_ESCAPE_ASCII_URI_COMPONENT = $00080000;    { Percent-encode all ASCII characters outside of the unreserved set from URI RFC 3986 (a-zA-Z0-9-.~_) (i.e.) No need for URL_ESCAPE_PERCENT along with this. }
+    URL_ESCAPE_URI_COMPONENT   = URL_ESCAPE_ASCII_URI_COMPONENT or URL_ESCAPE_AS_UTF8;
+    URL_UNESCAPE_URI_COMPONENT = URL_UNESCAPE_AS_UTF8;
+  {#endif // (NTDDI_VERSION >= NTDDI_WIN8) }
+    URL_ESCAPE_PERCENT         = $00001000;
+    URL_ESCAPE_SEGMENT_ONLY    = $00002000;    { Treat the entire URL param as one URL segment. }
+    URL_PARTFLAG_KEEPSCHEME    = $00000001;
+    URL_APPLY_DEFAULT          = $00000001;
+    URL_APPLY_GUESSSCHEME      = $00000002;
+    URL_APPLY_GUESSFILE        = $00000004;
+    URL_APPLY_FORCEAPPLY       = $00000008;
+    SRRF_RT_REG_NONE           = $00000001;  // restrict type to REG_NONE      (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_REG_SZ             = $00000002;  // restrict type to REG_SZ        (other data types will not return ERROR_SUCCESS) (automatically converts REG_EXPAND_SZ to REG_SZ unless SRRF_NOEXPAND is specified)
+    SRRF_RT_REG_EXPAND_SZ      = $00000004;  // restrict type to REG_EXPAND_SZ (other data types will not return ERROR_SUCCESS) (must specify SRRF_NOEXPAND or SHRegGetValue will fail with ERROR_INVALID_PARAMETER)
+    SRRF_RT_REG_BINARY         = $00000008;  // restrict type to REG_BINARY    (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_REG_DWORD          = $00000010;  // restrict type to REG_DWORD     (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_REG_MULTI_SZ       = $00000020;  // restrict type to REG_MULTI_SZ  (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_REG_QWORD          = $00000040;  // restrict type to REG_QWORD     (other data types will not return ERROR_SUCCESS)
+
+    SRRF_RT_DWORD              = (SRRF_RT_REG_BINARY or SRRF_RT_REG_DWORD); // restrict type to *32-bit* SRRF_RT_REG_BINARY or SRRF_RT_REG_DWORD (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_QWORD              = (SRRF_RT_REG_BINARY or SRRF_RT_REG_QWORD); // restrict type to *64-bit* SRRF_RT_REG_BINARY or SRRF_RT_REG_DWORD (other data types will not return ERROR_SUCCESS)
+    SRRF_RT_ANY                = $0000ffff;                               // no type restriction
+
+    SRRF_RM_ANY                = $00000000;  // no mode restriction (default is to allow any mode)
+    SRRF_RM_NORMAL             = $00010000;  // restrict system startup mode to "normal boot"               (other startup modes will not return ERROR_SUCCESS)
+    SRRF_RM_SAFE               = $00020000;  // restrict system startup mode to "safe mode"                 (other startup modes will not return ERROR_SUCCESS)
+    SRRF_RM_SAFENETWORK        = $00040000;  // restrict system startup mode to "safe mode with networking" (other startup modes will not return ERROR_SUCCESS)
+
+    SRRF_NOEXPAND              = $10000000;  // do not automatically expand environment strings if value is of type REG_EXPAND_SZ
+    SRRF_ZEROONFAILURE         = $20000000;  // if pvData is not NULL, set content to all zeros on failure
+    SRRF_NOVIRT                = $40000000;  // if the requested key is virtualized, then fail with ERROR_FILE_NOT_FOUND
+
+
+    SHREGSET_HKCU              = $00000001;       // Write to HKCU if empty.
+    SHREGSET_FORCE_HKCU        = $00000002;       // Write to HKCU.
+    SHREGSET_HKLM              = $00000004;       // Write to HKLM if empty.
+    SHREGSET_FORCE_HKLM        = $00000008;       // Write to HKLM.
+    SHREGSET_DEFAULT           = (SHREGSET_FORCE_HKCU or SHREGSET_HKLM);          // Default is SHREGSET_FORCE_HKCU | SHREGSET_HKLM.
+
+    //
+    //  Association APIs
+    //
+    //  these APIs are to assist in accessing the data in HKCR
+    //  getting the Command strings and exe paths
+    //  for different verbs and extensions are simplified this way
+    //
+
+
+    ASSOCF_NONE                = $00000000;
+    ASSOCF_INIT_NOREMAPCLSID   = $00000001;  //  do not remap clsids to progids
+    ASSOCF_INIT_BYEXENAME      = $00000002;  //  executable is being passed in
+    ASSOCF_OPEN_BYEXENAME      = $00000002;  //  executable is being passed in
+    ASSOCF_INIT_DEFAULTTOSTAR  = $00000004;  //  treat "*" as the BaseClass
+    ASSOCF_INIT_DEFAULTTOFOLDER= $00000008;  //  treat "Folder" as the BaseClass
+    ASSOCF_NOUSERSETTINGS      = $00000010;  //  dont use HKCU
+    ASSOCF_NOTRUNCATE          = $00000020;  //  dont truncate the return string
+    ASSOCF_VERIFY              = $00000040;  //  verify data is accurate (DISK HITS)
+    ASSOCF_REMAPRUNDLL         = $00000080;  //  actually gets info about rundlls target if applicable
+    ASSOCF_NOFIXUPS            = $00000100;  //  attempt to fix errors if found
+    ASSOCF_IGNOREBASECLASS     = $00000200;  //  dont recurse into the baseclass
+    ASSOCF_INIT_IGNOREUNKNOWN  = $00000400;  //  dont use the "Unknown" progid, instead fail
+    //#if (NTDDI_VERSION >= NTDDI_WIN8)
+    ASSOCF_INIT_FIXED_PROGID   = $00000800;  //  the Init() pszAssoc value is a ProgId that should not be mapped using the current user defaults
+    ASSOCF_IS_PROTOCOL         = $00001000;  //  the Init() pszAssoc value is an uri scheme (not including the ":") that should be mapped using the current user defaults
+    ASSOCF_INIT_FOR_FILE       = $00002000;  //  use this flag when specifying ASSOCF_INIT_FIXED_PROGID if the ProgId corresponds with a file extension based association
+    //#endif
+    //#if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
+    ASSOCF_IS_FULL_URI         = $00004000;  //  Used to specify that full http/https URI is being passed for target resolution
+                                             //  Only one of ASSOCF_INIT_FIXED_PROGID, ASSOCF_IS_PROTOCOL or ASSOCF_IS_FULL_URI can be specified at a time.
+    ASSOCF_PER_MACHINE_ONLY    = $00008000;  //  Enforces per-machine association look-up only and avoid HKCU.
+    //#endif
+
+    ASSOCF_APP_TO_APP          = $00010000;  // #if NTDDI_WIN10_RS4+
+
+
+
+    CTF_INSIST                 = $00000001;   // call pfnThreadProc synchronously if CreateThread() fails
+    CTF_THREAD_REF             = $00000002;   // hold a reference to the creating thread
+    CTF_PROCESS_REF            = $00000004;   // hold a reference to the creating process
+    CTF_COINIT_STA             = $00000008;   // init COM as STA for the created thread
+    CTF_COINIT                 = $00000008;   // init COM as STA for the created thread
+    CTF_FREELIBANDEXIT         = $00000010;   // hold a ref to the DLL and call FreeLibraryAndExitThread() when done IE6+
+    CTF_REF_COUNTED            = $00000020;   // thread supports ref counting via SHGetThreadRef() or CTF_THREAD_REF so that child threads can keep this thread alive IE6+
+    CTF_WAIT_ALLOWCOM          = $00000040;   // while waiting for pfnCallback, allow COM marshaling to the blocked calling thread IE6+
+
+    CTF_UNUSED                 = $00000080;   // IE7+
+    CTF_INHERITWOW64           = $00000100;   // new thread should inherit the wow64 disable state for the file system redirector IE7+
+
+
+    CTF_WAIT_NO_REENTRANCY  = $00000200;   // don't allow re-entrancy when waiting for the sync proc, this won't work with marshalled objects or SendMessages() from the sync proc Vista+
+
+    //#if (NTDDI_VERSION >= NTDDI_WIN7)
+    CTF_KEYBOARD_LOCALE        = $00000400;   // carry the keyboard locale from creating to created thread
+    CTF_OLEINITIALIZE          = $00000800;   // init OLE on the created thread (this will also init COM as STA)
+    CTF_COINIT_MTA             = $00001000;   // init COM as MTA for the created thread
+    CTF_NOADDREFLIB            = $00002000;   // this flag is the opposite of CTF_FREELIBANDEXIT that is now implicit as of Vista
+                                                    // this avoids the LoadLibrary/FreeLibraryAndExitThread calls that result in contention for the loader lock
+                                                    // only use this when the thread being created has some other means to ensure that the code
+                                                    // of the thread proc will remain loaded. This should not be used in the context of COM objects as those
+                                                    // need to ensure that the DLL stays loaded as COM will unload DLLs
+    //#endif // (NTDDI_VERSION >= NTDDI_WIN7)
+
+
+     OS_WINDOWS                  = 0;           // Windows 9x vs. NT
+     OS_NT                       = 1;           // Windows 9x vs. NT
+     OS_WIN95ORGREATER           = 2;           // Win95 or greater
+     OS_NT4ORGREATER             = 3;           // NT4 or greater
+     OS_WIN98ORGREATER           = 5;           // Win98 or greater
+     OS_WIN98_GOLD               = 6;           // Win98 Gold (Version 4.10 build 1998)
+     OS_WIN2000ORGREATER         = 7;           // Some derivative of Win2000
+
+// NOTE: these flags check explicitly for (dwMajorVersion == 5)
+     OS_WIN2000PRO               = 8;           // Windows 2000 Professional (Workstation)
+     OS_WIN2000SERVER            = 9;           // Windows 2000 Server
+     OS_WIN2000ADVSERVER         = 10;          // Windows 2000 Advanced Server
+     OS_WIN2000DATACENTER        = 11;          // Windows 2000 Data Center Server
+     OS_WIN2000TERMINAL          = 12;          // Windows 2000 Terminal Server in "Application Server" mode (now simply called "Terminal Server")
+
+     OS_EMBEDDED                 = 13;          // Embedded Windows Edition
+     OS_TERMINALCLIENT           = 14;          // Windows Terminal Client (eg user is comming in via tsclient)
+     OS_TERMINALREMOTEADMIN      = 15;          // Terminal Server in "Remote Administration" mode
+     OS_WIN95_GOLD               = 16;          // Windows 95 Gold (Version 4.0 Build 1995)
+     OS_MEORGREATER              = 17;          // Windows Millennium (Version 5.0)
+     OS_XPORGREATER              = 18;          // Windows XP or greater
+     OS_HOME                     = 19;          // Home Edition (eg NOT Professional, Server, Advanced Server, or Datacenter)
+     OS_PROFESSIONAL             = 20;          // Professional     (aka Workstation; eg NOT Server, Advanced Server, or Datacenter)
+     OS_DATACENTER               = 21;          // Datacenter       (eg NOT Server, Advanced Server, Professional, or Personal)
+     OS_ADVSERVER                = 22;          // Advanced Server  (eg NOT Datacenter, Server, Professional, or Personal)
+     OS_SERVER                   = 23;          // Server           (eg NOT Datacenter, Advanced Server, Professional, or Personal)
+     OS_TERMINALSERVER           = 24;          // Terminal Server - server running in what used to be called "Application Server" mode (now simply called "Terminal Server")
+     OS_PERSONALTERMINALSERVER   = 25;          // Personal Terminal Server - per/pro machine running in single user TS mode
+     OS_FASTUSERSWITCHING        = 26;          // Fast User Switching
+     OS_WELCOMELOGONUI           = 27;          // New friendly logon UI
+     OS_DOMAINMEMBER             = 28;          // Is this machine a member of a domain (eg NOT a workgroup)
+     OS_ANYSERVER                = 29;          // is this machine any type of server? (eg datacenter or advanced server or server)?
+     OS_WOW6432                  = 30;          // Is this process a 32-bit process running on an 64-bit platform?
+     OS_WEBSERVER                = 31;          // Web Edition Server
+     OS_SMALLBUSINESSSERVER      = 32;          // SBS Server
+     OS_TABLETPC                 = 33;          // Are we running on a TabletPC?
+     OS_SERVERADMINUI            = 34;          // Should defaults lean towards those preferred by server administrators?
+     OS_MEDIACENTER              = 35;          // eHome Freestyle Project
+     OS_APPLIANCE                = 36;          // Windows .NET Appliance Server
+     PERCEIVEDFLAG_UNDEFINED     = $0000;
+     PERCEIVEDFLAG_SOFTCODED     = $0001;
+     PERCEIVEDFLAG_HARDCODED     = $0002;
+     PERCEIVEDFLAG_NATIVESUPPORT = $0004;
+     PERCEIVEDFLAG_GDIPLUS       = $0010;
+     PERCEIVEDFLAG_WMSDK         = $0020;
+     PERCEIVEDFLAG_ZIPFOLDER     = $0040;
+
+  function  StrChrA(pszStart:PCSTR; wMatch:WORD):PCSTR;stdcall;external SHLWAPIDLL name 'StrChrA';
+  function  StrChrW(pszStart:PCWSTR; wMatch:WCHAR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrChrW';
+  function  StrChrIA(pszStart:PCSTR; wMatch:WORD):PCSTR;stdcall;external SHLWAPIDLL name 'StrChrIA';
+  function  StrChrIW(pszStart:PCWSTR; wMatch:WCHAR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrChrIW';
+  function  StrChrNW(pszStart:PCWSTR; wMatch:WCHAR; cchMax:UINT):PCWSTR;stdcall;external SHLWAPIDLL name 'StrChrNW';
+  function  StrChrNIW(pszStart:PCWSTR; wMatch:WCHAR; cchMax:UINT):PWSTR;stdcall;external SHLWAPIDLL name 'StrChrNIW';
+  function  StrCmpNA(psz1:PCSTR; psz2:PCSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNA';
+  function  StrCmpNW(psz1:PCWSTR; psz2:PCWSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNW';
+  function  StrCmpNIA(psz1:PCSTR; psz2:PCSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNIA';
+  function  StrCmpNIW(psz1:PCWSTR; psz2:PCWSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNIW';
+  function  StrCSpnA(pszStr:PCSTR; pszSet:PCSTR):longint;stdcall;external SHLWAPIDLL name 'StrCSpnA';
+  function  StrCSpnW(pszStr:PCWSTR; pszSet:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCSpnW';
+  function  StrCSpnIA(pszStr:PCSTR; pszSet:PCSTR):longint;stdcall;external SHLWAPIDLL name 'StrCSpnIA';
+  function  StrCSpnIW(pszStr:PCWSTR; pszSet:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCSpnIW';
+  function  StrDupA(pszSrch:PCSTR):PSTR;stdcall;external SHLWAPIDLL name 'StrDupA';
+  function  StrDupW(pszSrch:PCWSTR):PWSTR;stdcall;external SHLWAPIDLL name 'StrDupW';
+  function  StrFormatByteSizeEx(ull:ULONGLONG; flags:SFBS_FLAGS; pszBuf:PWSTR; cchBuf:UINT):HRESULT;stdcall;external SHLWAPIDLL name 'StrFormatByteSizeEx';
+  function  StrFormatByteSizeA(dw:DWORD; pszBuf:PSTR; cchBuf:UINT):PSTR;stdcall;external SHLWAPIDLL name 'StrFormatByteSizeA';
+  function  StrFormatByteSize64A(qdw:LONGLONG; pszBuf:PSTR; cchBuf:UINT):PSTR;stdcall;external SHLWAPIDLL name 'StrFormatByteSize64A';
+  function  StrFormatByteSizeW(qdw:LONGLONG; pszBuf:PWSTR; cchBuf:UINT):PWSTR;stdcall;external SHLWAPIDLL name 'StrFormatByteSizeW';
+  function  StrFormatKBSizeW(qdw:LONGLONG; pszBuf:PWSTR; cchBuf:UINT):PWSTR;stdcall;external SHLWAPIDLL name 'StrFormatKBSizeW';
+  function  StrFormatKBSizeA(qdw:LONGLONG; pszBuf:PSTR; cchBuf:UINT):PSTR;stdcall;external SHLWAPIDLL name 'StrFormatKBSizeA';
+  function  StrFromTimeIntervalA(pszOut:PSTR; cchMax:UINT; dwTimeMS:DWORD; digits:longint):longint;stdcall;external SHLWAPIDLL name 'StrFromTimeIntervalA';
+  function  StrFromTimeIntervalW(pszOut:PWSTR; cchMax:UINT; dwTimeMS:DWORD; digits:longint):longint;stdcall;external SHLWAPIDLL name 'StrFromTimeIntervalW';
+  function  StrIsIntlEqualA(fCaseSens:BOOL; pszString1:PCSTR; pszString2:PCSTR; nChar:longint):BOOL;stdcall;external SHLWAPIDLL name 'StrIsIntlEqualA';
+  function  StrIsIntlEqualW(fCaseSens:BOOL; pszString1:PCWSTR; pszString2:PCWSTR; nChar:longint):BOOL;stdcall;external SHLWAPIDLL name 'StrIsIntlEqualW';
+  function  StrNCatA(psz1:PSTR; psz2:PCSTR; cchMax:longint):PSTR;stdcall;external SHLWAPIDLL name 'StrNCatA';
+  function  StrNCatW(psz1:PWSTR; psz2:PCWSTR; cchMax:longint):PWSTR;stdcall;external SHLWAPIDLL name 'StrNCatW';
+  function  StrPBrkA(psz:PCSTR; pszSet:PCSTR):PCSTR;stdcall;external SHLWAPIDLL name 'StrPBrkA';
+  function  StrPBrkW(psz:PCWSTR; pszSet:PCWSTR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrPBrkW';
+  function  StrRChrA(pszStart:PCSTR; pszEnd:PCSTR; wMatch:WORD):PCSTR;stdcall;external SHLWAPIDLL name 'StrRChrA';
+  function  StrRChrW(pszStart:PCWSTR; pszEnd:PCWSTR; wMatch:WCHAR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrRChrW';
+  function  StrRChrIA(pszStart:PCSTR; pszEnd:PCSTR; wMatch:WORD):PCSTR;stdcall;external SHLWAPIDLL name 'StrRChrIA';
+  function  StrRChrIW(pszStart:PCWSTR; pszEnd:PCWSTR; wMatch:WCHAR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrRChrIW';
+  function  StrRStrIA(pszSource:PCSTR; pszLast:PCSTR; pszSrch:PCSTR):PCSTR;stdcall;external SHLWAPIDLL name 'StrRStrIA';
+  function  StrRStrIW(pszSource:PCWSTR; pszLast:PCWSTR; pszSrch:PCWSTR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrRStrIW';
+  function  StrSpnA(psz:PCSTR; pszSet:PCSTR):longint;stdcall;external SHLWAPIDLL name 'StrSpnA';
+  function  StrSpnW(psz:PCWSTR; pszSet:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrSpnW';
+  function  StrStrA(pszFirst:PCSTR; pszSrch:PCSTR):PCSTR;stdcall;external SHLWAPIDLL name 'StrStrA';
+  function  StrStrW(pszFirst:PCWSTR; pszSrch:PCWSTR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrStrW';
+  function  StrStrIA(pszFirst:PCSTR; pszSrch:PCSTR):PCSTR;stdcall;external SHLWAPIDLL name 'StrStrIA';
+  function  StrStrIW(pszFirst:PCWSTR; pszSrch:PCWSTR):PCWSTR;stdcall;external SHLWAPIDLL name 'StrStrIW';
+  function  StrStrNW(pszFirst:PCWSTR; pszSrch:PCWSTR; cchMax:UINT):PCWSTR;stdcall;external SHLWAPIDLL name 'StrStrNW';
+  function  StrStrNIW(pszFirst:PCWSTR; pszSrch:PCWSTR; cchMax:UINT):PCWSTR;stdcall;external SHLWAPIDLL name 'StrStrNIW';
+  function  StrToIntA(pszSrc:PCSTR):longint;stdcall;external SHLWAPIDLL name 'StrToIntA';
+  function  StrToIntW(pszSrc:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrToIntW';
+  function  StrToIntExA(pszString:PCSTR; dwFlags:STIF_FLAGS; piRet:plongint):BOOL;stdcall;external SHLWAPIDLL name 'StrToIntExA';
+  function  StrToIntExW(pszString:PCWSTR; dwFlags:STIF_FLAGS; piRet:plongint):BOOL;stdcall;external SHLWAPIDLL name 'StrToIntExW';
+  function  StrToInt64ExA(pszString:PCSTR; dwFlags:STIF_FLAGS; pllRet:pLONGLONG):BOOL;stdcall;external SHLWAPIDLL name 'StrToInt64ExA';
+  function  StrToInt64ExW(pszString:PCWSTR; dwFlags:STIF_FLAGS; pllRet:pLONGLONG):BOOL;stdcall;external SHLWAPIDLL name 'StrToInt64ExW';
+  function  StrTrimA(psz:PSTR; pszTrimChars:PCSTR):BOOL;stdcall;external SHLWAPIDLL name 'StrTrimA';
+  function  StrTrimW(psz:PWSTR; pszTrimChars:PCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'StrTrimW';
+  function  StrCatW(psz1:PWSTR; psz2:PCWSTR):PWSTR;stdcall;external SHLWAPIDLL name 'StrCatW';
+  function  StrCmpW(psz1:PCWSTR; psz2:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpW';
+  function  StrCmpIW(psz1:PCWSTR; psz2:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpIW';
+  function  StrCpyW(psz1:PWSTR; psz2:PCWSTR):PWSTR;stdcall;external SHLWAPIDLL name 'StrCpyW';
+  function  StrCpyNW(pszDst:PWSTR; pszSrc:PCWSTR; cchMax:longint):PWSTR;stdcall;external SHLWAPIDLL name 'StrCpyNW';
+  function  StrCatBuffW(pszDest:PWSTR; pszSrc:PCWSTR; cchDestBuffSize:longint):PWSTR;stdcall;external SHLWAPIDLL name 'StrCatBuffW';
+  function  StrCatBuffA(pszDest:PSTR; pszSrc:PCSTR; cchDestBuffSize:longint):PSTR;stdcall;external SHLWAPIDLL name 'StrCatBuffA';
+  function  ChrCmpIA(w1:WORD; w2:WORD):BOOL;stdcall;external SHLWAPIDLL name 'ChrCmpIA';
+  function  ChrCmpIW(w1:WCHAR; w2:WCHAR):BOOL;stdcall;external SHLWAPIDLL name 'ChrCmpIW';
+
+  function  StrRetToStrA(pstr:PSTRRET; pidl:PCUITEMID_CHILD; ppsz:PLPSTR):HRESULT;stdcall;external SHLWAPIDLL name 'StrRetToStrA';
+  function  StrRetToStrW(pstr:PSTRRET; pidl:PCUITEMID_CHILD; ppsz:PLPWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'StrRetToStrW';
+  function  StrRetToBufA(pstr:PSTRRET; pidl:PCUITEMID_CHILD; pszBuf:LPSTR; cchBuf:UINT):HRESULT;stdcall;external SHLWAPIDLL name 'StrRetToBufA';
+  function  StrRetToBufW(pstr:PSTRRET; pidl:PCUITEMID_CHILD; pszBuf:LPWSTR; cchBuf:UINT):HRESULT;stdcall;external SHLWAPIDLL name 'StrRetToBufW';
+  function  SHStrDupA(psz:LPCSTR; ppwsz:PLPWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'SHStrDupA';
+  function  SHStrDupW(psz:LPCWSTR; ppwsz:PLPWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'SHStrDupW';
+  function  StrCmpLogicalW(psz1:PCWSTR; psz2:PCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpLogicalW';
+  function  StrCatChainW(pszDst:PWSTR; cchDst:DWORD; ichAt:DWORD; pszSrc:PCWSTR):DWORD;stdcall;external SHLWAPIDLL name 'StrCatChainW';
+  function  StrRetToBSTR(pstr:PSTRRET; pidl:PCUITEMID_CHILD; out pbstr:BSTR):HRESULT;stdcall;external SHLWAPIDLL name 'StrRetToBSTR';
+  function  SHLoadIndirectString(pszSource:PCWSTR; pszOutBuf:PWSTR; cchOutBuf:UINT; ppvReserved:Ppointer):HRESULT;stdcall;external SHLWAPIDLL name 'SHLoadIndirectString';
+  function  IsCharSpaceA(wch:CHAR):BOOL;stdcall;external SHLWAPIDLL name 'IsCharSpaceA';
+  function  IsCharSpaceW(wch:WCHAR):BOOL;stdcall;external SHLWAPIDLL name 'IsCharSpaceW';
+  function  StrCmpCA(pszStr1:LPCSTR; pszStr2:LPCSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpCA';
+  function  StrCmpCW(pszStr1:LPCWSTR; pszStr2:LPCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpCW';
+  function  StrCmpICA(pszStr1:LPCSTR; pszStr2:LPCSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpICA';
+  function  StrCmpICW(pszStr1:LPCWSTR; pszStr2:LPCWSTR):longint;stdcall;external SHLWAPIDLL name 'StrCmpICW';
+  function  StrCmpNCA(pszStr1:LPCSTR; pszStr2:LPCSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNCA';
+  function  StrCmpNCW(pszStr1:LPCWSTR; pszStr2:LPCWSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNCW';
+  function  StrCmpNICA(pszStr1:LPCSTR; pszStr2:LPCSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNICA';
+  function  StrCmpNICW(pszStr1:LPCWSTR; pszStr2:LPCWSTR; nChar:longint):longint;stdcall;external SHLWAPIDLL name 'StrCmpNICW';
+  function  IntlStrEqWorkerA(fCaseSens:BOOL; lpString1:LPCSTR; lpString2:LPCSTR; nChar:longint):BOOL;stdcall;external SHLWAPIDLL name 'IntlStrEqWorkerA';
+  function  IntlStrEqWorkerW(fCaseSens:BOOL; lpString1:LPCWSTR; lpString2:LPCWSTR; nChar:longint):BOOL;stdcall;external SHLWAPIDLL name 'IntlStrEqWorkerW';
+  function  PathAddBackslashA(pszPath:LPSTR):LPSTR;stdcall;external SHLWAPIDLL name 'PathAddBackslashA';
+  function  PathAddBackslashW(pszPath:LPWSTR):LPWSTR;stdcall;external SHLWAPIDLL name 'PathAddBackslashW';
+  function  PathAddExtensionA(pszPath:LPSTR; pszExt:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathAddExtensionA';
+  function  PathAddExtensionW(pszPath:LPWSTR; pszExt:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathAddExtensionW';
+  function  PathAppendA(pszPath:LPSTR; pszMore:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathAppendA';
+  function  PathAppendW(pszPath:LPWSTR; pszMore:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathAppendW';
+  function  PathBuildRootA(pszRoot:LPSTR; iDrive:longint):LPSTR;stdcall;external SHLWAPIDLL name 'PathBuildRootA';
+  function  PathBuildRootW(pszRoot:LPWSTR; iDrive:longint):LPWSTR;stdcall;external SHLWAPIDLL name 'PathBuildRootW';
+  function  PathCanonicalizeA(pszBuf:LPSTR; pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathCanonicalizeA';
+  function  PathCanonicalizeW(pszBuf:LPWSTR; pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathCanonicalizeW';
+  function  PathCombineA(pszDest:LPSTR; pszDir:LPCSTR; pszFile:LPCSTR):LPSTR;stdcall;external SHLWAPIDLL name 'PathCombineA';
+  function  PathCombineW(pszDest:LPWSTR; pszDir:LPCWSTR; pszFile:LPCWSTR):LPWSTR;stdcall;external SHLWAPIDLL name 'PathCombineW';
+  function  PathCompactPathA(hDC:HDC; pszPath:LPSTR; dx:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathCompactPathA';
+  function  PathCompactPathW(hDC:HDC; pszPath:LPWSTR; dx:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathCompactPathW';
+  function  PathCompactPathExA(pszOut:LPSTR; pszSrc:LPCSTR; cchMax:UINT; dwFlags:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathCompactPathExA';
+  function  PathCompactPathExW(pszOut:LPWSTR; pszSrc:LPCWSTR; cchMax:UINT; dwFlags:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathCompactPathExW';
+  function  PathCommonPrefixA(pszFile1:LPCSTR; pszFile2:LPCSTR; achPath:LPSTR):longint;stdcall;external SHLWAPIDLL name 'PathCommonPrefixA';
+  function  PathCommonPrefixW(pszFile1:LPCWSTR; pszFile2:LPCWSTR; achPath:LPWSTR):longint;stdcall;external SHLWAPIDLL name 'PathCommonPrefixW';
+  function  PathFileExistsA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathFileExistsA';
+  function  PathFileExistsW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathFileExistsW';
+  function  PathFindExtensionA(pszPath:LPCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'PathFindExtensionA';
+  function  PathFindExtensionW(pszPath:LPCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathFindExtensionW';
+  function  PathFindFileNameA(pszPath:LPCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'PathFindFileNameA';
+  function  PathFindFileNameW(pszPath:LPCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathFindFileNameW';
+  function  PathFindNextComponentA(pszPath:LPCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'PathFindNextComponentA';
+  function  PathFindNextComponentW(pszPath:LPCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathFindNextComponentW';
+  function  PathFindOnPathA(pszPath:LPSTR; ppszOtherDirs:PZPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathFindOnPathA';
+  function  PathFindOnPathW(pszPath:LPWSTR; ppszOtherDirs:PZPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathFindOnPathW';
+  function  PathFindSuffixArrayA(pszPath:LPCSTR; apszSuffix:PLPSTR; iArraySize:longint):LPCSTR;stdcall;external SHLWAPIDLL name 'PathFindSuffixArrayA';
+  function  PathFindSuffixArrayW(pszPath:LPCWSTR; apszSuffix:PLPWSTR; iArraySize:longint):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathFindSuffixArrayW';
+  function  PathGetArgsA(pszPath:LPCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'PathGetArgsA';
+  function  PathGetArgsW(pszPath:LPCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathGetArgsW';
+  function  PathIsLFNFileSpecA(pszName:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsLFNFileSpecA';
+  function  PathIsLFNFileSpecW(pszName:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsLFNFileSpecW';
+  function  PathGetCharTypeA(ch:UCHAR):Uint;stdcall;external SHLWAPIDLL name 'PathGetCharTypeA';
+  function  PathGetCharTypeW(ch:WCHAR):Uint;stdcall;external SHLWAPIDLL name 'PathGetCharTypeW';
+  function  PathGetDriveNumberA(pszPath:LPCSTR):longint;stdcall;external SHLWAPIDLL name 'PathGetDriveNumberA';
+  function  PathGetDriveNumberW(pszPath:LPCWSTR):longint;stdcall;external SHLWAPIDLL name 'PathGetDriveNumberW';
+  function  PathIsDirectoryA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsDirectoryA';
+  function  PathIsDirectoryW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsDirectoryW';
+  function  PathIsDirectoryEmptyA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsDirectoryEmptyA';
+  function  PathIsDirectoryEmptyW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsDirectoryEmptyW';
+  function  PathIsFileSpecA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsFileSpecA';
+  function  PathIsFileSpecW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsFileSpecW';
+  function  PathIsPrefixA(pszPrefix:LPCSTR; pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsPrefixA';
+  function  PathIsPrefixW(pszPrefix:LPCWSTR; pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsPrefixW';
+  function  PathIsRelativeA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsRelativeA';
+  function  PathIsRelativeW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsRelativeW';
+  function  PathIsRootA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsRootA';
+  function  PathIsRootW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsRootW';
+  function  PathIsSameRootA(pszPath1:LPCSTR; pszPath2:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsSameRootA';
+  function  PathIsSameRootW(pszPath1:LPCWSTR; pszPath2:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsSameRootW';
+  function  PathIsUNCA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCA';
+  function  PathIsUNCW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCW';
+  function  PathIsNetworkPathA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsNetworkPathA';
+  function  PathIsNetworkPathW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsNetworkPathW';
+  function  PathIsUNCServerA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCServerA';
+  function  PathIsUNCServerW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCServerW';
+  function  PathIsUNCServerShareA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCServerShareA';
+  function  PathIsUNCServerShareW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsUNCServerShareW';
+  function  PathIsContentTypeA(pszPath:LPCSTR; pszContentType:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsContentTypeA';
+  function  PathIsContentTypeW(pszPath:LPCWSTR; pszContentType:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsContentTypeW';
+  function  PathIsURLA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsURLA';
+  function  PathIsURLW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathIsURLW';
+  function  PathMakePrettyA(pszPath:LPSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMakePrettyA';
+  function  PathMakePrettyW(pszPath:LPWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMakePrettyW';
+  function  PathMatchSpecA(pszFile:LPCSTR; pszSpec:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMatchSpecA';
+  function  PathMatchSpecW(pszFile:LPCWSTR; pszSpec:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMatchSpecW';
+  function  PathMatchSpecExA(pszFile:LPCSTR; pszSpec:LPCSTR; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'PathMatchSpecExA';
+  function  PathMatchSpecExW(pszFile:LPCWSTR; pszSpec:LPCWSTR; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'PathMatchSpecExW';
+  function  PathParseIconLocationA(pszIconFile:LPSTR):longint;stdcall;external SHLWAPIDLL name 'PathParseIconLocationA';
+  function  PathParseIconLocationW(pszIconFile:LPWSTR):longint;stdcall;external SHLWAPIDLL name 'PathParseIconLocationW';
+  function  PathQuoteSpacesA(lpsz:LPSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathQuoteSpacesA';
+  function  PathQuoteSpacesW(lpsz:LPWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathQuoteSpacesW';
+  function  PathRelativePathToA(pszPath:LPSTR; pszFrom:LPCSTR; dwAttrFrom:DWORD; pszTo:LPCSTR; dwAttrTo:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathRelativePathToA';
+  function  PathRelativePathToW(pszPath:LPWSTR; pszFrom:LPCWSTR; dwAttrFrom:DWORD; pszTo:LPCWSTR; dwAttrTo:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathRelativePathToW';
+  procedure PathRemoveArgsA(pszPath:LPSTR);stdcall;external SHLWAPIDLL name 'PathRemoveArgsA';
+  procedure PathRemoveArgsW(pszPath:LPWSTR);stdcall;external SHLWAPIDLL name 'PathRemoveArgsW';
+  function  PathRemoveBackslashA(pszPath:LPSTR):LPSTR;stdcall;external SHLWAPIDLL name 'PathRemoveBackslashA';
+  function  PathRemoveBackslashW(pszPath:LPWSTR):LPWSTR;stdcall;external SHLWAPIDLL name 'PathRemoveBackslashW';
+  procedure PathRemoveBlanksA(pszPath:LPSTR);stdcall;external SHLWAPIDLL name 'PathRemoveBlanksA';
+  procedure PathRemoveBlanksW(pszPath:LPWSTR);stdcall;external SHLWAPIDLL name 'PathRemoveBlanksW';
+  procedure PathRemoveExtensionA(pszPath:LPSTR);stdcall;external SHLWAPIDLL name 'PathRemoveExtensionA';
+  procedure PathRemoveExtensionW(pszPath:LPWSTR);stdcall;external SHLWAPIDLL name 'PathRemoveExtensionW';
+  function  PathRemoveFileSpecA(pszPath:LPSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathRemoveFileSpecA';
+  function  PathRemoveFileSpecW(pszPath:LPWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathRemoveFileSpecW';
+  function  PathRenameExtensionA(pszPath:LPSTR; pszExt:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathRenameExtensionA';
+  function  PathRenameExtensionW(pszPath:LPWSTR; pszExt:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathRenameExtensionW';
+  function  PathSearchAndQualifyA(pszPath:LPCSTR; pszBuf:LPSTR; cchBuf:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathSearchAndQualifyA';
+  function  PathSearchAndQualifyW(pszPath:LPCWSTR; pszBuf:LPWSTR; cchBuf:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathSearchAndQualifyW';
+  procedure PathSetDlgItemPathA(hDlg:HWND; id:longint; pszPath:LPCSTR);stdcall;external SHLWAPIDLL name 'PathSetDlgItemPathA';
+  procedure PathSetDlgItemPathW(hDlg:HWND; id:longint; pszPath:LPCWSTR);stdcall;external SHLWAPIDLL name 'PathSetDlgItemPathW';
+  function  PathSkipRootA(pszPath:LPCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'PathSkipRootA';
+  function  PathSkipRootW(pszPath:LPCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'PathSkipRootW';
+  procedure PathStripPathA(pszPath:LPSTR);stdcall;external SHLWAPIDLL name 'PathStripPathA';
+  procedure PathStripPathW(pszPath:LPWSTR);stdcall;external SHLWAPIDLL name 'PathStripPathW';
+  function  PathStripToRootA(pszPath:LPSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathStripToRootA';
+  function  PathStripToRootW(pszPath:LPWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathStripToRootW';
+  function  PathUnquoteSpacesA(lpsz:LPSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathUnquoteSpacesA';
+  function  PathUnquoteSpacesW(lpsz:LPWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathUnquoteSpacesW';
+  function  PathMakeSystemFolderA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMakeSystemFolderA';
+  function  PathMakeSystemFolderW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathMakeSystemFolderW';
+  function  PathUnmakeSystemFolderA(pszPath:LPCSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathUnmakeSystemFolderA';
+  function  PathUnmakeSystemFolderW(pszPath:LPCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'PathUnmakeSystemFolderW';
+  function  PathIsSystemFolderA(pszPath:LPCSTR; dwAttrb:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathIsSystemFolderA';
+  function  PathIsSystemFolderW(pszPath:LPCWSTR; dwAttrb:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'PathIsSystemFolderW';
+  procedure PathUndecorateA(pszPath:LPSTR);stdcall;external SHLWAPIDLL name 'PathUndecorateA';
+  procedure PathUndecorateW(pszPath:LPWSTR);stdcall;external SHLWAPIDLL name 'PathUndecorateW';
+  function  PathUnExpandEnvStringsA(pszPath:LPCSTR; pszBuf:LPSTR; cchBuf:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathUnExpandEnvStringsA';
+  function  PathUnExpandEnvStringsW(pszPath:LPCWSTR; pszBuf:LPWSTR; cchBuf:UINT):BOOL;stdcall;external SHLWAPIDLL name 'PathUnExpandEnvStringsW';
+  function  UrlCompareA(psz1:PCSTR; psz2:PCSTR; fIgnoreSlash:BOOL):longint;stdcall;external SHLWAPIDLL name 'UrlCompareA';
+  function  UrlCompareW(psz1:PCWSTR; psz2:PCWSTR; fIgnoreSlash:BOOL):longint;stdcall;external SHLWAPIDLL name 'UrlCompareW';
+  function  UrlCombineA(pszBase:PCSTR; pszRelative:PCSTR; pszCombined:PSTR; pcchCombined:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCombineA';
+  function  UrlCombineW(pszBase:PCWSTR; pszRelative:PCWSTR; pszCombined:PWSTR; pcchCombined:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCombineW';
+  function  UrlCanonicalizeA(pszUrl:PCSTR; pszCanonicalized:PSTR; pcchCanonicalized:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCanonicalizeA';
+  function  UrlCanonicalizeW(pszUrl:PCWSTR; pszCanonicalized:PWSTR; pcchCanonicalized:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCanonicalizeW';
+  function  UrlIsOpaqueA(pszURL:PCSTR):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsOpaqueA';
+  function  UrlIsOpaqueW(pszURL:PCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsOpaqueW';
+  function  UrlIsNoHistoryA(pszURL:PCSTR):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsNoHistoryA';
+  function  UrlIsNoHistoryW(pszURL:PCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsNoHistoryW';
+  function  UrlIsA(pszUrl:PCSTR; UrlIs:URLIS):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsA';
+  function  UrlIsW(pszUrl:PCWSTR; UrlIs:URLIS):BOOL;stdcall;external SHLWAPIDLL name 'UrlIsW';
+  function  UrlGetLocationA(pszURL:PCSTR):LPCSTR;stdcall;external SHLWAPIDLL name 'UrlGetLocationA';
+  function  UrlGetLocationW(pszURL:PCWSTR):LPCWSTR;stdcall;external SHLWAPIDLL name 'UrlGetLocationW';
+  function  UrlUnescapeA(pszUrl:PSTR; pszUnescaped:PSTR; pcchUnescaped:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlUnescapeA';
+  function  UrlUnescapeW(pszUrl:PWSTR; pszUnescaped:PWSTR; pcchUnescaped:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlUnescapeW';
+  function  UrlEscapeA(pszUrl:PCSTR; pszEscaped:PSTR; pcchEscaped:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlEscapeA';
+  function  UrlEscapeW(pszUrl:PCWSTR; pszEscaped:PWSTR; pcchEscaped:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlEscapeW';
+  function  UrlCreateFromPathA(pszPath:PCSTR; pszUrl:PSTR; pcchUrl:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCreateFromPathA';
+  function  UrlCreateFromPathW(pszPath:PCWSTR; pszUrl:PWSTR; pcchUrl:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlCreateFromPathW';
+  function  PathCreateFromUrlA(pszUrl:PCSTR; pszPath:PSTR; pcchPath:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'PathCreateFromUrlA';
+  function  PathCreateFromUrlW(pszUrl:PCWSTR; pszPath:PWSTR; pcchPath:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'PathCreateFromUrlW';
+  function  PathCreateFromUrlAlloc(pszIn:PCWSTR; out ppszOut:PWSTR; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'PathCreateFromUrlAlloc';
+  function  UrlHashA(pszUrl:PCSTR; pbHash:PBYTE; cbHash:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlHashA';
+  function  UrlHashW(pszUrl:PCWSTR; pbHash:PBYTE; cbHash:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlHashW';
+  function  UrlGetPartW(pszIn:PCWSTR; pszOut:PWSTR; pcchOut:PDWORD; dwPart:DWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlGetPartW';
+  function  UrlGetPartA(pszIn:PCSTR; pszOut:PSTR; pcchOut:PDWORD; dwPart:DWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlGetPartA';
+  function  UrlApplySchemeA(pszIn:PCSTR; pszOut:PSTR; pcchOut:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlApplySchemeA';
+  function  UrlApplySchemeW(pszIn:PCWSTR; pszOut:PWSTR; pcchOut:PDWORD; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlApplySchemeW';
+  function  HashData(pbData:PBYTE; cbData:DWORD; pbHash:PBYTE; cbHash:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'HashData';
+  function  UrlFixupW(pcszUrl:PCWSTR; pszTranslatedUrl:PWSTR; cchMax:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'UrlFixupW';
+  function SHDeleteEmptyKeyA(hKey:HKEY; pszSubKey:LPCSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteEmptyKeyA';
+  function SHDeleteEmptyKeyW(hKey:HKEY; pszSubKey:LPCWSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteEmptyKeyW';
+  function SHDeleteKeyA(hKey:HKEY; pszSubKey:LPCSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteKeyA';
+  function SHDeleteKeyW(hKey:HKEY; pszSubKey:LPCWSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteKeyW';
+  function SHRegDuplicateHKey(hKey:HKEY):HKEY;stdcall;external SHLWAPIDLL name 'SHRegDuplicateHKey';
+  function SHDeleteValueA(hKey:HKEY; pszSubKey:LPCSTR; pszValue:LPCSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteValueA';
+  function SHDeleteValueW(hKey:HKEY; pszSubKey:LPCWSTR; pszValue:LPCWSTR):LSTATUS;stdcall;external SHLWAPIDLL name 'SHDeleteValueW';
+  {LSTATUS    SHGetValueA( }
+  {LSTATUS    SHGetValueW( }
+  function SHSetValueA(hKey:HKEY; pszSubKey:LPCSTR; pszValue:LPCSTR; dwType:DWORD; pvData:LPCVOID;
+             cbData:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHSetValueA';
+  function SHSetValueW(hKey:HKEY; pszSubKey:LPCWSTR; pszValue:LPCWSTR; dwType:DWORD; pvData:LPCVOID;
+             cbData:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHSetValueW';
+  function SHRegGetValueA(hKey:HKEY; pszSubKey:LPCSTR; pszValue:LPCSTR; srrfFlags:SRRF; pdwType:PDWORD;
+             pvData:pointer; pcbData:PDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegGetValueA';
+  function SHRegGetValueW(hKey:HKEY; pszSubKey:LPCWSTR; pszValue:LPCWSTR; srrfFlags:SRRF; pdwType:PDWORD;
+             pvData:pointer; pcbData:PDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegGetValueW';
+  function SHRegSetValue(hkey:HKEY; pszSubKey:LPCWSTR; pszValue:LPCWSTR; srrfFlags:SRRF; dwType:DWORD;
+             pvData:LPCVOID; cbData:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegSetValue';
+
+  function SHRegGetValueFromHKCUHKLM(pwszKey:PCWSTR; pwszValue:PCWSTR; srrfFlags:SRRF; pdwType:PDWORD; pvData:pointer;
+             pcbData:PDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegGetValueFromHKCUHKLM';
+
+  function SHQueryValueExA(hkey:HKEY; pszValue:LPCSTR; pdwReserved:PDWORD; pdwType:PDWORD; pvData:pointer;
+             pcbData:PDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHQueryValueExA';
+
+  function SHQueryValueExW(hkey:HKEY; pszValue:LPCWSTR; pdwReserved:PDWORD; pdwType:PDWORD; pvData:pointer;
+             pcbData:PDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHQueryValueExW';
+
+  function SHEnumKeyExA(hKey:HKEY; dwIndex:DWORD; pszName:LPSTR; pcchName:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHEnumKeyExA';
+
+  function SHEnumKeyExW(hKey:HKEY; dwIndex:DWORD; pszName:LPWSTR; pcchName:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHEnumKeyExW';
+
+  function SHEnumValueA(hKey:HKEY; dwIndex:DWORD; pszValueName:PSTR; pcchValueName:LPDWORD; pdwType:LPDWORD;
+             pvData:pointer; pcbData:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHEnumValueA';
+
+  function SHEnumValueW(hKey:HKEY; dwIndex:DWORD; pszValueName:PWSTR; pcchValueName:LPDWORD; pdwType:LPDWORD;
+             pvData:pointer; pcbData:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHEnumValueW';
+
+  function SHQueryInfoKeyA(hKey:HKEY; pcSubKeys:LPDWORD; pcchMaxSubKeyLen:LPDWORD; pcValues:LPDWORD; pcchMaxValueNameLen:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHQueryInfoKeyA';
+
+  function SHQueryInfoKeyW(hKey:HKEY; pcSubKeys:LPDWORD; pcchMaxSubKeyLen:LPDWORD; pcValues:LPDWORD; pcchMaxValueNameLen:LPDWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHQueryInfoKeyW';
+
+  function SHCopyKeyA(_hKeySrc:HKEY; pszSrcSubKey:LPCSTR; _hKeyDest:HKEY; fReserved:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHCopyKeyA';
+
+  function SHCopyKeyW(_hKeySrc:HKEY; pszSrcSubKey:LPCWSTR; _hKeyDest:HKEY; fReserved:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHCopyKeyW';
+
+  function SHRegGetPathA(hKey:HKEY; pcszSubKey:LPCSTR; pcszValue:LPCSTR; pszPath:LPSTR; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegGetPathA';
+
+  function SHRegGetPathW(hKey:HKEY; pcszSubKey:LPCWSTR; pcszValue:LPCWSTR; pszPath:LPWSTR; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegGetPathW';
+
+  function SHRegSetPathA(hKey:HKEY; pcszSubKey:LPCSTR; pcszValue:LPCSTR; pcszPath:LPCSTR; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegSetPathA';
+
+  function SHRegSetPathW(hKey:HKEY; pcszSubKey:LPCWSTR; pcszValue:LPCWSTR; pcszPath:LPCWSTR; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegSetPathW';
+
+  function SHRegCreateUSKeyA(pszPath:LPCSTR; samDesired:REGSAM; hRelativeUSKey:HUSKEY; phNewUSKey:PHUSKEY; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegCreateUSKeyA';
+
+  function SHRegCreateUSKeyW(pwzPath:LPCWSTR; samDesired:REGSAM; hRelativeUSKey:HUSKEY; phNewUSKey:PHUSKEY; dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegCreateUSKeyW';
+
+  function SHRegOpenUSKeyA(pszPath:LPCSTR; samDesired:REGSAM; hRelativeUSKey:HUSKEY; phNewUSKey:PHUSKEY; fIgnoreHKCU:BOOL):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegOpenUSKeyA';
+
+  function SHRegOpenUSKeyW(pwzPath:LPCWSTR; samDesired:REGSAM; hRelativeUSKey:HUSKEY; phNewUSKey:PHUSKEY; fIgnoreHKCU:BOOL):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegOpenUSKeyW';
+
+  function SHRegQueryUSValueA(hUSKey:HUSKEY; pszValue:LPCSTR; pdwType:PDWORD; pvData:pointer; pcbData:PDWORD;
+             fIgnoreHKCU:BOOL; pvDefaultData:pointer; dwDefaultDataSize:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegQueryUSValueA';
+
+  function SHRegQueryUSValueW(hUSKey:HUSKEY; pszValue:LPCWSTR; pdwType:PDWORD; pvData:pointer; pcbData:PDWORD;
+             fIgnoreHKCU:BOOL; pvDefaultData:pointer; dwDefaultDataSize:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegQueryUSValueW';
+
+(* Const before type ignored *)
+  function SHRegWriteUSValueA(hUSKey:HUSKEY; pszValue:LPCSTR; dwType:DWORD; pvData:pointer; cbData:DWORD;
+             dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegWriteUSValueA';
+
+(* Const before type ignored *)
+  function SHRegWriteUSValueW(hUSKey:HUSKEY; pwzValue:LPCWSTR; dwType:DWORD; pvData:pointer; cbData:DWORD;
+             dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegWriteUSValueW';
+
+  function SHRegDeleteUSValueA(hUSKey:HUSKEY; pszValue:LPCSTR; delRegFlags:SHREGDEL_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegDeleteUSValueA';
+
+  function SHRegDeleteUSValueW(hUSKey:HUSKEY; pwzValue:LPCWSTR; delRegFlags:SHREGDEL_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegDeleteUSValueW';
+
+  function SHRegDeleteEmptyUSKeyW(hUSKey:HUSKEY; pwzSubKey:LPCWSTR; delRegFlags:SHREGDEL_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegDeleteEmptyUSKeyW';
+
+  function SHRegDeleteEmptyUSKeyA(hUSKey:HUSKEY; pszSubKey:LPCSTR; delRegFlags:SHREGDEL_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegDeleteEmptyUSKeyA';
+
+  function SHRegEnumUSKeyA(hUSKey:HUSKEY; dwIndex:DWORD; pszName:LPSTR; pcchName:LPDWORD; enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegEnumUSKeyA';
+
+  function SHRegEnumUSKeyW(hUSKey:HUSKEY; dwIndex:DWORD; pwzName:LPWSTR; pcchName:LPDWORD; enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegEnumUSKeyW';
+
+  function SHRegEnumUSValueA(hUSkey:HUSKEY; dwIndex:DWORD; pszValueName:LPSTR; pcchValueName:LPDWORD; pdwType:LPDWORD;
+             pvData:pointer; pcbData:LPDWORD; enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegEnumUSValueA';
+
+  function SHRegEnumUSValueW(hUSkey:HUSKEY; dwIndex:DWORD; pszValueName:LPWSTR; pcchValueName:LPDWORD; pdwType:LPDWORD;
+             pvData:pointer; pcbData:LPDWORD; enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegEnumUSValueW';
+
+  function SHRegQueryInfoUSKeyA(hUSKey:HUSKEY; pcSubKeys:LPDWORD; pcchMaxSubKeyLen:LPDWORD; pcValues:LPDWORD; pcchMaxValueNameLen:LPDWORD;
+             enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegQueryInfoUSKeyA';
+
+  function SHRegQueryInfoUSKeyW(hUSKey:HUSKEY; pcSubKeys:LPDWORD; pcchMaxSubKeyLen:LPDWORD; pcValues:LPDWORD; pcchMaxValueNameLen:LPDWORD;
+             enumRegFlags:SHREGENUM_FLAGS):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegQueryInfoUSKeyW';
+
+  function SHRegCloseUSKey(hUSKey:HUSKEY):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegCloseUSKey';
+
+(* Const before type ignored *)
+  function SHRegSetUSValueA(pszSubKey:LPCSTR; pszValue:LPCSTR; dwType:DWORD; pvData:pointer; cbData:DWORD;
+             dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegSetUSValueA';
+
+(* Const before type ignored *)
+  function SHRegSetUSValueW(pwzSubKey:LPCWSTR; pwzValue:LPCWSTR; dwType:DWORD; pvData:pointer; cbData:DWORD;
+             dwFlags:DWORD):LSTATUS;stdcall;external SHLWAPIDLL name 'SHRegSetUSValueW';
+
+  function SHRegGetIntW(hk:HKEY; pwzKey:PCWSTR; iDefault:longint):longint;stdcall;external SHLWAPIDLL name 'SHRegGetIntW';
+  function SHRegGetBoolUSValueA(pszSubKey:LPCSTR; pszValue:LPCSTR; fIgnoreHKCU:BOOL; fDefault:BOOL):BOOL;stdcall;external SHLWAPIDLL name 'SHRegGetBoolUSValueA';
+  function SHRegGetBoolUSValueW(pszSubKey:LPCWSTR; pszValue:LPCWSTR; fIgnoreHKCU:BOOL; fDefault:BOOL):BOOL;stdcall;external SHLWAPIDLL name 'SHRegGetBoolUSValueW';
+  function AssocCreate(clsid:CLSID; riid:REFIID; ppv:Ppointer):HRESULT;stdcall;external SHLWAPIDLL name 'AssocCreate';
+  function AssocQueryStringA(flags:ASSOCF; str:ASSOCSTR; pszAssoc:LPCSTR; pszExtra:LPCSTR; pszOut:LPSTR;
+             pcchOut:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryStringA';
+  function AssocQueryStringW(flags:ASSOCF; str:ASSOCSTR; pszAssoc:LPCWSTR; pszExtra:LPCWSTR; pszOut:LPWSTR;
+             pcchOut:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryStringW';
+  function AssocQueryStringByKeyA(flags:ASSOCF; str:ASSOCSTR; hkAssoc:HKEY; pszExtra:LPCSTR; pszOut:LPSTR;
+             pcchOut:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryStringByKeyA';
+  function AssocQueryStringByKeyW(flags:ASSOCF; str:ASSOCSTR; hkAssoc:HKEY; pszExtra:LPCWSTR; pszOut:LPWSTR;
+             pcchOut:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryStringByKeyW';
+  function AssocQueryKeyA(flags:ASSOCF; key:ASSOCKEY; pszAssoc:LPCSTR; pszExtra:LPCSTR; phkeyOut:PHKEY):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryKeyA';
+  function AssocQueryKeyW(flags:ASSOCF; key:ASSOCKEY; pszAssoc:LPCWSTR; pszExtra:LPCWSTR; phkeyOut:PHKEY):HRESULT;stdcall;external SHLWAPIDLL name 'AssocQueryKeyW';
+  function AssocIsDangerous(pszAssoc:PCWSTR):BOOL;stdcall;external SHLWAPIDLL name 'AssocIsDangerous';
+  { these are cdecl varargs }
+ function wvnsprintfA(pszDest : PSTR;cchDest : WINT; pszFmt:PCSTR ):integer;  cdecl;varargs; external SHLWAPIDLL name 'wvnsprintfA';
+ function wvnsprintfW(pszDest :PWSTR;cchDest : WINT; pszFmt:PCWSTR ):integer; cdecl;varargs; external SHLWAPIDLL name 'wvnsprintfW';
+ function wnsprintfA (pszDest : PSTR;cchDest : WINT; pszFmt:PCSTR ):integer;  cdecl;varargs; external SHLWAPIDLL name 'wnsprintfA';
+ function wnsprintfW (pszDest :PWSTR;cchDest : WINT; pszFmt:PCWSTR ):integer; cdecl;varargs; external SHLWAPIDLL name 'wnsprintfW';
+
+ function  ParseURLA(pcszURL:LPCSTR; ppu:PPARSEDURLA):HRESULT;stdcall;external SHLWAPIDLL name 'ParseURLA';
+ function  ParseURLW(pcszURL:LPCWSTR; ppu:PPARSEDURLW):HRESULT;stdcall;external SHLWAPIDLL name 'ParseURLW';
+
+ function AssocGetPerceivedType(pszExt:PCWSTR; ptype:PPERCEIVED; pflag:PPERCEIVEDFLAG; ppszType:PLPWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'AssocGetPerceivedType';
+ function SHOpenRegStreamA(hKey:HKEY; pszSubkey:LPCSTR; pszValue:LPCSTR; grfMode:DWORD):IStream;stdcall;external SHLWAPIDLL name 'SHOpenRegStreamA';
+ function SHOpenRegStreamW(hKey:HKEY; pszSubkey:LPCWSTR; pszValue:LPCWSTR; grfMode:DWORD):IStream;stdcall;external SHLWAPIDLL name 'SHOpenRegStreamW';
+ function SHOpenRegStream2A(hKey:HKEY; pszSubkey:LPCSTR; pszValue:LPCSTR; grfMode:DWORD):IStream;stdcall;external SHLWAPIDLL name 'SHOpenRegStream2A';
+ function SHOpenRegStream2W(hKey:HKEY; pszSubkey:LPCWSTR; pszValue:LPCWSTR; grfMode:DWORD):IStream;stdcall;external SHLWAPIDLL name 'SHOpenRegStream2W';
+ function SHCreateStreamOnFileA(pszFile:LPCSTR; grfMode:DWORD; out ppstm:IStream):HRESULT;stdcall;external SHLWAPIDLL name 'SHCreateStreamOnFileA';
+ function SHCreateStreamOnFileW(pszFile:LPCWSTR; grfMode:DWORD; out ppstm:IStream):HRESULT;stdcall;external SHLWAPIDLL name 'SHCreateStreamOnFileW';
+ function SHCreateStreamOnFileEx(pszFile:LPCWSTR; grfMode:DWORD; dwAttributes:DWORD; fCreate:BOOL; pstmTemplate:IStream;
+            out ppstm:IStream):HRESULT;stdcall;external SHLWAPIDLL name 'SHCreateStreamOnFileEx';
+(* Const before type ignored *)
+ function SHCreateMemStream(pInit:PBYTE; cbInit:UINT):IStream;stdcall;external SHLWAPIDLL name 'SHCreateMemStream';
+ function GetAcceptLanguagesA(pszLanguages:LPSTR; pcchLanguages:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'GetAcceptLanguagesA';
+ function GetAcceptLanguagesW(pszLanguages:LPWSTR;  pcchLanguages:PDWORD):HRESULT;stdcall;external SHLWAPIDLL name 'GetAcceptLanguagesW';
+ procedure IUnknown_Set(out ppunk:IUnknown; punk:IUnknown);stdcall;external SHLWAPIDLL name 'IUnknown_Set';
+ procedure IUnknown_AtomicRelease(ppunk:Ppointer);stdcall;external SHLWAPIDLL name 'IUnknown_AtomicRelease';
+
+ function IUnknown_GetWindow(punk:IUnknown; phwnd:PHWND):HRESULT;stdcall;external SHLWAPIDLL name 'IUnknown_GetWindow';
+ function IUnknown_SetSite( punk:IUnknown; punkSite:IUnknown):HRESULT;stdcall;external SHLWAPIDLL name 'IUnknown_SetSite';
+ function IUnknown_GetSite( punk:IUnknown; riid:REFIID; ppv:Ppointer):HRESULT;stdcall;external SHLWAPIDLL name 'IUnknown_GetSite';
+ function IUnknown_QueryService(punk:IUnknown; constref guidService:TGUID; riid:REFIID; ppvOut:Ppointer):HRESULT;stdcall;external SHLWAPIDLL name 'IUnknown_QueryService';
+ { _COM_Outptr_  }
+ function IStream_Read(out pstm:IStream; pv:pointer; cb:ULONG):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_Read';
+
+(* Const before type ignored *)
+ function IStream_Write(out pstm:IStream; pv:pointer; cb:ULONG):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_Write';
+
+ function IStream_Reset(out pstm:IStream):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_Reset';
+
+ function IStream_Size(pstm:IStream; pui:PULARGE_INTEGER):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_Size';
+
+ function ConnectToConnectionPoint( punk:IUnknown; riidEvent:REFIID; fConnect:BOOL;  punkTarget:IUnknown; pdwCookie:PDWORD;
+            out ppcpOut:IConnectionPoint):HRESULT;stdcall;external SHLWAPIDLL name 'ConnectToConnectionPoint';
+
+ function IStream_ReadPidl(pstm:IStream; ppidlOut:PPIDLIST_RELATIVE):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_ReadPidl';
+ function IStream_WritePidl(pstm:IStream; pidlWrite:PCUIDLIST_RELATIVE):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_WritePidl';
+ function IStream_ReadStr(pstm:IStream; ppsz:PLPWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_ReadStr';
+ function IStream_WriteStr(pstm:IStream; psz:PCWSTR):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_WriteStr';
+ function IStream_Copy(pstmFrom:IStream; pstmTo:IStream; cb:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'IStream_Copy';
+ function SHGetViewStatePropertyBag(pidl:PCIDLIST_ABSOLUTE; pszBagName:PCWSTR; dwFlags:DWORD; riid:REFIID; ppv:Ppointer):HRESULT;stdcall;external SHLWAPIDLL name 'SHGetViewStatePropertyBag';
+
+(* Const before type ignored *)
+ function SHFormatDateTimeA(pft:PFILETIME; pdwFlags:PDWORD; pszBuf:LPSTR; cchBuf:UINT):longint;stdcall;external SHLWAPIDLL name 'SHFormatDateTimeA';
+
+(* Const before type ignored *)
+ function SHFormatDateTimeW(pft:PFILETIME;  pdwFlags:PDWORD; pszBuf:LPWSTR; cchBuf:UINT):longint;stdcall;external SHLWAPIDLL name 'SHFormatDateTimeW';
+
+ { filetime unaligned }
+ function SHAnsiToUnicode(pszSrc:PCSTR; pwszDst:PWSTR; cwchBuf:longint):longint;stdcall;external SHLWAPIDLL name 'SHAnsiToUnicode';
+
+ function SHAnsiToAnsi(pszSrc:PCSTR; pszDst:PSTR; cchBuf:longint):longint;stdcall;external SHLWAPIDLL name 'SHAnsiToAnsi';
+
+ function SHUnicodeToAnsi(pwszSrc:PCWSTR; pszDst:PSTR; cchBuf:longint):longint;stdcall;external SHLWAPIDLL name 'SHUnicodeToAnsi';
+
+ function SHUnicodeToUnicode(pwzSrc:PCWSTR; pwzDst:PWSTR; cwchBuf:longint):longint;stdcall;external SHLWAPIDLL name 'SHUnicodeToUnicode';
+
+ function SHMessageBoxCheckA(hwnd:HWND; pszText:LPCSTR; pszCaption:LPCSTR; uType:UINT; iDefault:longint;
+            pszRegVal:LPCSTR):longint;stdcall;external SHLWAPIDLL name 'SHMessageBoxCheckA';
+
+ function SHMessageBoxCheckW(hwnd:HWND; pszText:LPCWSTR; pszCaption:LPCWSTR; uType:UINT; iDefault:longint;
+            pszRegVal:LPCWSTR):longint;stdcall;external SHLWAPIDLL name 'SHMessageBoxCheckW';
+
+ function SHSendMessageBroadcastA(uMsg:UINT; wParam:WPARAM; lParam:LPARAM):LRESULT;stdcall;external SHLWAPIDLL name 'SHSendMessageBroadcastA';
+ function SHSendMessageBroadcastW(uMsg:UINT; wParam:WPARAM; lParam:LPARAM):LRESULT;stdcall;external SHLWAPIDLL name 'SHSendMessageBroadcastW';
+ function SHStripMneumonicA(pszMenu:LPSTR):CHAR;stdcall;external SHLWAPIDLL name 'SHStripMneumonicA';
+ function SHStripMneumonicW(pszMenu:LPWSTR):WCHAR;stdcall;external SHLWAPIDLL name 'SHStripMneumonicW';
+ function IsOS(dwOS:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'IsOS';
+(* Const before type ignored *)
+ function SHGlobalCounterGetValue(id:SHGLOBALCOUNTER):longint;stdcall;external SHLWAPIDLL name 'SHGlobalCounterGetValue';
+
+(* Const before type ignored *)
+ function SHGlobalCounterIncrement(id:SHGLOBALCOUNTER):longint;stdcall;external SHLWAPIDLL name 'SHGlobalCounterIncrement';
+
+(* Const before type ignored *)
+ function SHGlobalCounterDecrement(id:SHGLOBALCOUNTER):longint;stdcall;external SHLWAPIDLL name 'SHGlobalCounterDecrement';
+
+(* Const before type ignored *)
+ function SHAllocShared(pvData:pointer; dwSize:DWORD; dwProcessId:DWORD):HANDLE;stdcall;external SHLWAPIDLL name 'SHAllocShared';
+ function SHFreeShared(hData:HANDLE; dwProcessId:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'SHFreeShared';
+ function SHLockShared(hData:HANDLE; dwProcessId:DWORD):pointer;stdcall;external SHLWAPIDLL name 'SHLockShared';
+ function SHUnlockShared(pvData:pointer):BOOL;stdcall;external SHLWAPIDLL name 'SHUnlockShared';
+ function WhichPlatform:UINT;stdcall;external SHLWAPIDLL name 'WhichPlatform';
+ function SHIsLowMemoryMachine(dwType:DWORD):BOOL;stdcall;external SHLWAPIDLL name 'SHIsLowMemoryMachine';
+ function GetMenuPosFromID(hmenu:HMENU; id:UINT):longint;stdcall;external SHLWAPIDLL name 'GetMenuPosFromID';
+ function SHGetInverseCMAP(pbMap:PBYTE; cbMap:ULONG):HRESULT;stdcall;external SHLWAPIDLL name 'SHGetInverseCMAP';
+ function SHAutoComplete(hwndEdit:HWND; dwFlags:DWORD):HRESULT;stdcall;external SHLWAPIDLL name 'SHAutoComplete';
+ function SHCreateThreadRef(pcRef:PLONG; out ppunk:IUnknown):HRESULT;stdcall;external SHLWAPIDLL name 'SHCreateThreadRef';
+ function SHSetThreadRef(punk:IUnknown):HRESULT;stdcall;external SHLWAPIDLL name 'SHSetThreadRef';
+ function SHGetThreadRef(out ppunk:IUnknown):HRESULT;stdcall;external SHLWAPIDLL name 'SHGetThreadRef';
+
+ { _COM_Outptr_ }
+(* Const before type ignored *)
+ function SHSkipJunction(pbc:IBindCtx; pclsid:PCLSID):BOOL;stdcall;external SHLWAPIDLL name 'SHSkipJunction';
+ function SHCreateThread(pfnThreadProc:LPTHREAD_START_ROUTINE; pData:pointer; flags:SHCT_FLAGS; pfnCallback:LPTHREAD_START_ROUTINE):BOOL;stdcall;external SHLWAPIDLL name 'SHCreateThread';
+ function SHCreateThreadWithHandle(pfnThreadProc:LPTHREAD_START_ROUTINE; pData:pointer; flags:SHCT_FLAGS; pfnCallback:LPTHREAD_START_ROUTINE; pHandle:PHANDLE):BOOL;stdcall;external SHLWAPIDLL name 'SHCreateThreadWithHandle';
+ procedure SetProcessReference( punk:IUnknown);stdcall;external SHLWAPIDLL name 'SetProcessReference';
+ function GetProcessReference(punk:IUnknown):HRESULT;stdcall;external SHLWAPIDLL name 'GetProcessReference';
+ {_COM_Outptr_ }
+ function SHReleaseThreadRef:HRESULT;stdcall;external SHLWAPIDLL name 'SHReleaseThreadRef';
+ { release a CTF_THREAD_REF reference earlier than the return of pfnThreadProc }
+ function SHCreateShellPalette(hdc:HDC):HPALETTE;stdcall;external SHLWAPIDLL name 'SHCreateShellPalette';
+ procedure ColorRGBToHLS(clrRGB:COLORREF; pwHue:PWORD; pwLuminance:PWORD; pwSaturation:PWORD);stdcall;external SHLWAPIDLL name 'ColorRGBToHLS';
+ function ColorHLSToRGB(wHue:WORD; wLuminance:WORD; wSaturation:WORD):COLORREF;stdcall;external SHLWAPIDLL name 'ColorHLSToRGB';
+ function ColorAdjustLuma(clrRGB:COLORREF; n:longint; fScale:BOOL):COLORREF;stdcall;external SHLWAPIDLL name 'ColorAdjustLuma';
+ function IsInternetESCEnabled:BOOL;stdcall;external SHLWAPIDLL name 'IsInternetESCEnabled';
 
 
 implementation
 implementation
 
 
-end.
+end.

+ 41 - 31
rtl/avr/avr.inc

@@ -32,37 +32,43 @@ procedure fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif}
 
 
 
 
 {$define FPC_SYSTEM_HAS_MOVE}
 {$define FPC_SYSTEM_HAS_MOVE}
-procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE'];
-var
-  pdest,psrc,pend : pbyte;
-begin
-  if (@dest=@source) or (count<=0) then
-    exit;
-  if (@dest<@source) or (@source+count<@dest) then
-    begin
-      { Forward Move }
-      psrc:=@source;
-      pdest:=@dest;
-      pend:=psrc+count;
-      while psrc<pend do
-        begin
-          pdest^:=psrc^;
-          inc(pdest);
-          inc(psrc);
-        end;
-    end
-  else
-    begin
-      { Backward Move }
-      psrc:=@source+count;
-      pdest:=@dest+count;
-      while psrc>@source do
-        begin
-          dec(pdest);
-          dec(psrc);
-          pdest^:=psrc^;
-        end;
-    end;
+procedure Move(const source;var dest;count:SizeInt);[public, alias: 'FPC_MOVE']; assembler; nostackframe;
+asm
+  push r28
+  push r29
+
+  movw r26, r24         // Src=X
+  movw r28, r22         // Dest=Y
+  movw r30, r20         // Count=Z
+  cp r1, r30
+  cpc r1, r31
+  brge .Lexit           // if 0 >= Count
+  cp  r28, r26
+  cpc r29, r27
+  breq .Lexit           // if dest = source
+  brlo .LForwardMove    // if dest < source
+
+  // Add count to both pointers
+  add r26, r30
+  adc r27, r31
+  add r28, r30
+  adc r29, r31
+.LBackwardMove:
+  ld r18, -X
+  st -Y, r18
+  sbiw Z, 1
+  brne .LBackwardMove
+  rjmp .Lexit
+
+.LForwardMove:
+  ld r18, X+
+  st Y+, r18
+  sbiw Z, 1
+  brne .LForwardMove
+.Lexit:
+
+  pop r29
+  pop r28
 end;
 end;
 
 
 
 
@@ -107,6 +113,8 @@ function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler;no
 {$define FPC_SYSTEM_HAS_SPTR}
 {$define FPC_SYSTEM_HAS_SPTR}
 Function Sptr : pointer;assembler;nostackframe;
 Function Sptr : pointer;assembler;nostackframe;
   asm
   asm
+    in r24, 0x3d
+    in r25, 0x3e
   end;
   end;
 
 
 
 
@@ -261,3 +269,5 @@ function InterLockedExchangeAdd (var Target: smallint;Source : smallint) : small
     avr_restore(temp_sreg);
     avr_restore(temp_sreg);
   end;
   end;
 
 
+{include hand-optimized assembler code}
+{$i math.inc}

+ 254 - 0
rtl/avr/math.inc

@@ -13,3 +13,257 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 
  **********************************************************************}
  **********************************************************************}
+
+// Based on restoring division algorithm
+// Algorithm source document: Lecture notes by S. Galal and D. Pham, Division algorithms and hardware implementations.
+// Link to documentation http://www.seas.ucla.edu/~ingrid/ee213a/lectures/division_presentV2.pdf
+// Also refer to description on Wikipedia: https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
+
+// Note that the algorithm automatically yields the following results for special cases:
+// z div 0 = MAX(type)
+// 0 div 0 = MAX(type)
+// 0 div n = 0
+// Checks for z = 0; n = [0,1]; n = z and n > z could shortcut the algorithm for speed-ups
+// but would add extra code
+// Perhaps add the checks depending on optimization settings?
+
+// z (dividend) = q(quotient) x n(divisor) + p(remainder)
+
+{$ifndef FPC_SYSTEM_HAS_DIV_BYTE}
+{$define FPC_SYSTEM_HAS_DIV_BYTE}
+
+// z in Ra, n in Rb, 0 in Rp
+function fpc_div_byte(n, z: byte): byte; assembler; nostackframe;
+{$ifdef FPC_IS_SYSTEM}[public,alias: 'FPC_DIV_BYTE'];{$endif}
+label
+  start, div1, div2, div3, finish;
+asm
+// Symbol  Name        Register(s)
+// z (A)   dividend    R22
+// n (B)   divisor     R24
+// p (P)   remainder   R20
+// i	   counter     R18
+
+  cp R24, R1
+  brne start
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_pc_addr
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_pc_addr
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R20, R24
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_frame
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_frame
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R18, R24
+  ldi R22, 200
+  clr R23
+  clr R24
+  clr R25
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call HandleErrorAddrFrameInd
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall HandleErrorAddrFrameInd
+{$endif CPUAVR_HAS_JMP_CALL}
+
+
+start:
+  clr R20         // clear remainder
+  ldi R18, 8      // iterate over 8 bits
+
+div1:
+  lsl R22         // shift left A
+  rol R20         // shift left P with carry from A shift
+  sub R20, R24    // Subtract B from P, P <= P - B
+  brlo div2
+  ori R22, 1      // Set A[0] = 1
+  rjmp div3
+div2:             // negative branch, A[0] = 0 (default after shift), restore P
+  add R20, R24    // restore old value of P
+
+div3:
+  dec R18
+  brne div1
+
+finish:
+  mov R24, R22    // Move result from R22 to R24
+end;
+
+{It is a compilerproc (systemh.inc), make an alias for internal use.}
+{$ifdef FPC_IS_SYSTEM}
+function fpc_div_byte(n, z: byte): byte; external name 'FPC_DIV_BYTE';
+{$endif FPC_IS_SYSTEM}
+{$endif FPC_SYSTEM_HAS_DIV_BYTE}
+
+{$ifndef FPC_SYSTEM_HAS_DIV_WORD}
+{$define FPC_SYSTEM_HAS_DIV_WORD}
+
+// z in Ra, n in Rb, 0 in Rp
+function fpc_div_word(n, z: word): word; assembler; nostackframe;
+{$ifdef FPC_IS_SYSTEM}[public,alias: 'FPC_DIV_WORD'];{$endif}
+label
+  start, div1, div2, div3, finish;
+asm
+// Symbol  Name        Register(s)
+// z (A)   dividend    R23, R22
+// n (B)   divisor     R25, R24
+// p (P)   remainder   R21, R20
+// i	   counter     R18
+
+  cp R24, R1
+  brne start
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_pc_addr
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_pc_addr
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R20, R24
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_frame
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_frame
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R18, R24
+  ldi R22, 200
+  clr R23
+  clr R24
+  clr R25
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call HandleErrorAddrFrameInd
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall HandleErrorAddrFrameInd
+{$endif CPUAVR_HAS_JMP_CALL}
+
+start:            // Start of division...
+  clr R20         // clear remainder low
+  clr R21         // clear remainder hi
+  ldi R18, 16     // iterate over 16 bits
+
+div1:
+  lsl R22         // shift left A_L
+  rol R23
+  rol R20         // shift left P with carry from A shift
+  rol R21
+  sub R20, R24    // Subtract B from P, P <= P - B
+  sbc R21, R25
+  brlo div2
+  ori R22, 1      // Set A[0] = 1
+  rjmp div3
+div2:             // negative branch, A[0] = 0 (default after shift), restore P
+  add R20, R24    // restore old value of P
+  adc R21, R25
+
+div3:
+  dec R18
+  brne div1
+
+finish:
+  movw R24, R22    // Move result from R22:R23 to R24:R25
+end;
+
+{It is a compilerproc (systemh.inc), make an alias for internal use.}
+{$ifdef FPC_IS_SYSTEM}
+function fpc_div_word(n, z: word): word; external name 'FPC_DIV_WORD';
+{$endif FPC_IS_SYSTEM}
+{$endif FPC_SYSTEM_HAS_DIV_WORD}
+
+
+{$ifndef FPC_SYSTEM_HAS_DIV_DWORD}
+{$define FPC_SYSTEM_HAS_DIV_DWORD}
+
+// z in Ra, n in Rb, 0 in Rp
+function fpc_div_dword(n, z: dword): dword; assembler; nostackframe;
+{$ifdef FPC_IS_SYSTEM}[public,alias: 'FPC_DIV_DWORD'];{$endif}
+label
+  start, div1, div2, div3, finish;
+asm
+// Symbol  Name        Register(s)
+// z (A)   dividend    R21, R20, R19, R18
+// n (B)   divisor     R25, R24, R23, R22
+// p (P)   remainder   R17, R16, R15, R14
+// i	   counter     R26
+
+  cp R24, R1
+  cpc R25, R1
+  cpc R22, R1
+  cpc R23, R1
+  brne .LNonZero
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_pc_addr
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_pc_addr
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R20, R24
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call get_frame
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall get_frame
+{$endif CPUAVR_HAS_JMP_CALL}
+  movw R18, R24
+  ldi R22, 200
+  clr R23
+  clr R24
+  clr R25
+{$ifdef CPUAVR_HAS_JMP_CALL}
+  call HandleErrorAddrFrameInd
+{$else  CPUAVR_HAS_JMP_CALL}
+  rcall HandleErrorAddrFrameInd
+{$endif CPUAVR_HAS_JMP_CALL}
+
+.LNonZero:
+  push R17
+  push R16
+  push R15
+  push R14
+
+start:            // Start of division...
+  clr R14         // clear remainder
+  clr R15         // clear remainder
+  clr R16
+  clr R17
+  ldi R26, 32     // iterate over 32 bits
+
+div1:
+  lsl R18         // shift left A_L
+  rol R19
+  rol R20
+  rol R21
+  rol R14         // shift left P with carry from A shift
+  rol R15
+  rol R16
+  rol R17
+  sub R14, R22    // Subtract B from P, P <= P - B
+  sbc R15, R23
+  sbc R16, R24
+  sbc R17, R25
+  brlo div2
+  ori R18, 1      // Set A[0] = 1
+  rjmp div3
+div2:             // negative branch, A[0] = 0 (default after shift), restore P
+  add R14, R22    // restore old value of P
+  adc R15, R23
+  adc R16, R24
+  adc R17, R25
+
+div3:
+  dec R26
+  brne div1
+
+finish:
+  movw R22, R18    // Move result from R18:R21 to R22:R25
+  movw R24, R20
+
+  pop R14
+  pop R15
+  pop R16
+  pop R17
+end;
+
+{It is a compilerproc (systemh.inc), make an alias for internal use.}
+{$ifdef FPC_IS_SYSTEM}
+function fpc_div_dword(n, z: dword): dword; external name 'FPC_DIV_DWORD';
+{$endif FPC_IS_SYSTEM}
+{$endif FPC_SYSTEM_HAS_DIV_DWORD}
+

+ 10 - 0
rtl/avr/setjump.inc

@@ -49,6 +49,11 @@ function fpc_setjmp(var S : jmp_buf) : shortint;assembler;[Public, alias : 'FPC_
     pop r19
     pop r19
     st x+,r18
     st x+,r18
     st x+,r19
     st x+,r19
+{$ifdef CPUAVR_3_BYTE_PC}
+    pop r20
+    st x+,r20
+    push r20
+{$endif CPUAVR_3_BYTE_PC}
     push r19
     push r19
     push r18
     push r18
 
 
@@ -94,6 +99,11 @@ procedure fpc_longjmp(var S : jmp_buf;value : shortint);assembler;[Public, alias
     pop r19
     pop r19
     ld r18,x+
     ld r18,x+
     ld r19,x+
     ld r19,x+
+{$ifdef CPUAVR_3_BYTE_PC}
+    pop r20
+    ld r20,x+
+    push r20
+{$endif CPUAVR_3_BYTE_PC}
     push r19
     push r19
     push r18
     push r18
     mov r24,r22
     mov r24,r22

+ 3 - 0
rtl/avr/setjumph.inc

@@ -17,6 +17,9 @@
 type
 type
    jmp_buf = packed record
    jmp_buf = packed record
      r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r28,r29,splo,sphi,pclo,pchi : byte;
      r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r28,r29,splo,sphi,pclo,pchi : byte;
+{$ifdef CPUAVR_3_BYTE_PC}
+     pchighest : byte
+{$endif CPUAVR_3_BYTE_PC}
    end;
    end;
    pjmp_buf = ^jmp_buf;
    pjmp_buf = ^jmp_buf;
 
 

+ 7 - 0
rtl/beos/ossysc.inc

@@ -789,6 +789,13 @@ begin
 end;
 end;
 
 
 
 
+Function Fpmprotect(start:pointer;len:size_t;prot:cint):cint; [public, alias : 'FPC_SYSC_MPROTECT'];
+begin
+  {$warning TODO BeOS Fpmprotect implementation}
+//  Fpmprotect:=do_syscall(syscall_nr_mprotect,TSysParam(start),TSysParam(len),TSysParam(prot));
+end;
+
+
 {
 {
   Interface to Unix ioctl call.
   Interface to Unix ioctl call.
   Performs various operations on the filedescriptor Handle.
   Performs various operations on the filedescriptor Handle.

+ 6 - 0
rtl/bsd/ossysc.inc

@@ -470,6 +470,12 @@ begin
 end;
 end;
 
 
 
 
+Function Fpmprotect(start:pointer;len:size_t;prot:cint):cint; [public, alias : 'FPC_SYSC_MPROTECT'];
+begin
+  Fpmprotect:=do_syscall(syscall_nr_mprotect,TSysParam(start),TSysParam(len),TSysParam(prot));
+end;
+
+
 {
 {
   Interface to Unix ioctl call.
   Interface to Unix ioctl call.
   Performs various operations on the filedescriptor Handle.
   Performs various operations on the filedescriptor Handle.

+ 12 - 2
rtl/embedded/system.pp

@@ -20,6 +20,8 @@ Unit System;
                                     interface
                                     interface
 {*****************************************************************************}
 {*****************************************************************************}
 
 
+{$define FPC_SYSTEM_HAS_STACKTOP}
+
 {$define FPC_IS_SYSTEM}
 {$define FPC_IS_SYSTEM}
 {$define HAS_CMDLINE}
 {$define HAS_CMDLINE}
 
 
@@ -203,6 +205,14 @@ const calculated_cmdline:Pchar=nil;
 {*****************************************************************************
 {*****************************************************************************
                        Misc. System Dependent Functions
                        Misc. System Dependent Functions
 *****************************************************************************}
 *****************************************************************************}
+var
+ _stack_top: record end; external name '_stack_top';
+
+function StackTop: pointer;
+begin
+  StackTop:=@_stack_top;
+end;
+
 
 
 procedure haltproc;cdecl;external name '_haltproc';
 procedure haltproc;cdecl;external name '_haltproc';
 
 
@@ -277,7 +287,7 @@ begin
 end;
 end;
 
 
 var
 var
-  initialstkptr : Pointer; // external name '__stkptr';
+  initialstkptr : record end; external name '_stack_top';
 {$endif FPC_HAS_FEATURE_STACKCHECK}
 {$endif FPC_HAS_FEATURE_STACKCHECK}
 
 
 begin
 begin
@@ -294,7 +304,7 @@ begin
 
 
 {$ifdef FPC_HAS_FEATURE_STACKCHECK}
 {$ifdef FPC_HAS_FEATURE_STACKCHECK}
   StackLength := CheckInitialStkLen(initialStkLen);
   StackLength := CheckInitialStkLen(initialStkLen);
-  StackBottom := initialstkptr - StackLength;
+  StackBottom := @initialstkptr - StackLength;
 {$endif FPC_HAS_FEATURE_STACKCHECK}
 {$endif FPC_HAS_FEATURE_STACKCHECK}
 
 
 {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
 {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}

+ 1 - 0
rtl/freebsd/sysnr.inc

@@ -104,6 +104,7 @@ const
  syscall_nr_waitpid                     =   7;
  syscall_nr_waitpid                     =   7;
  syscall_nr_write                       =   4;
  syscall_nr_write                       =   4;
  syscall_nr_munmap                      =  73;
  syscall_nr_munmap                      =  73;
+ syscall_nr_mprotect                    =  74;
  syscall_nr_getsockopt                  = 118;
  syscall_nr_getsockopt                  = 118;
  syscall_nr_rfork                       = 251;
  syscall_nr_rfork                       = 251;
  syscall_nr_clock_gettime               = 232;
  syscall_nr_clock_gettime               = 232;

+ 10 - 1
rtl/inc/getopts.pp

@@ -15,7 +15,8 @@
  **********************************************************************}
  **********************************************************************}
 unit getopts;
 unit getopts;
 Interface
 Interface
-
+{$modeswitch advancedrecords}
+{$modeswitch defaultparameters}
 Const
 Const
   No_Argument       = 0;
   No_Argument       = 0;
   Required_Argument = 1;
   Required_Argument = 1;
@@ -29,6 +30,7 @@ Type
     Has_arg : Integer;
     Has_arg : Integer;
     Flag    : PChar;
     Flag    : PChar;
     Value   : Char;
     Value   : Char;
+    Procedure SetOption(const aName:String;AHas_Arg:integer=0;AFlag:PChar=nil;AValue:Char=#0);
   end;
   end;
 
 
   Orderings = (require_order,permute,return_in_order);
   Orderings = (require_order,permute,return_in_order);
@@ -48,6 +50,13 @@ Function GetLongOpts (ShortOpts : String;LongOpts : POption;var Longind : Longin
 
 
 Implementation
 Implementation
 
 
+
+Procedure TOption.SetOption(const aName:String;AHas_Arg:integer=0;AFlag:PChar=nil;AValue:Char=#0);
+begin
+  Name:=aName; Has_Arg:=AHas_Arg; Flag:=AFlag; Value:=Avalue;
+end;
+
+
 {$IFNDEF FPC}
 {$IFNDEF FPC}
 {***************************************************************************
 {***************************************************************************
                                Create an ArgV
                                Create an ArgV

+ 4 - 0
rtl/inc/system.inc

@@ -44,7 +44,11 @@ type
 {$endif FPC_HAS_FEATURE_TEXTIO}
 {$endif FPC_HAS_FEATURE_TEXTIO}
 
 
 const
 const
+{$ifdef CPUAVR}
+  STACK_MARGIN = 64;    { Stack size margin for stack checking }
+{$else}
   STACK_MARGIN = 16384;    { Stack size margin for stack checking }
   STACK_MARGIN = 16384;    { Stack size margin for stack checking }
+{$endif}
 { Random / Randomize constants }
 { Random / Randomize constants }
   OldRandSeed : Cardinal = 0;
   OldRandSeed : Cardinal = 0;
 
 

+ 63 - 3
rtl/linux/arm/sighnd.inc

@@ -15,9 +15,52 @@
 
 
  **********************************************************************}
  **********************************************************************}
 
 
+function GetHandleErrorAddrFrameAddr: pointer;
+begin
+  result:=@HandleErrorAddrFrame;
+end;
 
 
-procedure SignalToRunerror(Sig: longint; { _a2,_a3,_a4 : dword; } SigContext: PSigInfo; uContext : PuContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl;
+{$ifndef CPUTHUMB}
+Procedure SignalToHandleErrorAddrFrame_ARM(Errno : longint;addr : CodePointer; frame : Pointer); nostackframe; assembler;
+asm
+{$if FPC_VERSION >= 30200}
+.code 32
+{$endif}
+  // the address is of the faulting instruction, and sigreturn will
+  //  skip it -> start with a nop
+  nop
+  push {r0,r1,r2,r3}
+  bl GetHandleErrorAddrFrameAddr
+  // overwrite last stack slot with new return address
+  str r0, [sp,#12]
+  // lr := addr
+  ldr lr, [sp,#4]
+  pop {r0,r1,r2,pc}
+.text
+end;
+{$endif not CPUTHUMB}
+
+{$if FPC_VERSION >= 30200}
+Procedure SignalToHandleErrorAddrFrame_Thumb(Errno : longint;addr : CodePointer; frame : Pointer); nostackframe; assembler;
+asm
+.thumb_func
+.code 16
+  // the address is of the faulting instruction, and sigreturn will
+  // skip it -> start with a nop
+  nop
+  push {r0,r1,r2,r3}
+  bl GetHandleErrorAddrFrameAddr
+  // overwrite last stack slot with new return address
+  str r0, [sp,#12]
+  // lr := addr
+  ldr r0, [sp,#4]
+  mov lr, r0
+  pop {r0,r1,r2,pc}
+.text
+end;
+{$endif}
 
 
+procedure SignalToRunerror(Sig: longint; { _a2,_a3,_a4 : dword; } SigContext: PSigInfo; uContext : PuContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl;
 var
 var
   res : word;
   res : word;
 begin
 begin
@@ -48,10 +91,27 @@ begin
     SIGQUIT:
     SIGQUIT:
         res:=233;
         res:=233;
   end;
   end;
-  reenable_signal(sig);
   { give runtime error at the position where the signal was raised }
   { give runtime error at the position where the signal was raised }
   if res<>0 then
   if res<>0 then
-    HandleErrorAddrFrame(res,pointer(uContext^.uc_mcontext.arm_pc),pointer(uContext^.uc_mcontext.arm_fp));
+    begin
+      ucontext^.uc_mcontext.arm_r0:=res;
+      ucontext^.uc_mcontext.arm_r1:=uContext^.uc_mcontext.arm_pc;
+      ucontext^.uc_mcontext.arm_r2:=uContext^.uc_mcontext.arm_fp;
+{$if FPC_VERSION >= 30200}
+{$ifndef CPUTHUMB}
+      if (ucontext^.uc_mcontext.arm_cpsr and (1 shl 5))=0 then
+        begin
+          ucontext^.uc_mcontext.arm_pc:=ptruint(@SignalToHandleErrorAddrFrame_ARM);
+        end
+      else
+{$endif not CPUTHUMB}
+        begin
+          ucontext^.uc_mcontext.arm_pc:=ptruint(@SignalToHandleErrorAddrFrame_Thumb);
+        end;
+{$else}
+      ucontext^.uc_mcontext.arm_pc:=ptruint(@SignalToHandleErrorAddrFrame_ARM);
+{$endif}
+    end;
 end;
 end;
 
 
 
 

+ 6 - 0
rtl/linux/ossysc.inc

@@ -603,6 +603,12 @@ begin
   Fpmunmap:=do_syscall(syscall_nr_munmap,TSysParam(Adr),TSysParam(Len));
   Fpmunmap:=do_syscall(syscall_nr_munmap,TSysParam(Adr),TSysParam(Len));
 end;
 end;
 
 
+
+Function Fpmprotect(adr:pointer;len:size_t;prot:cint):cint; [public, alias : 'FPC_SYSC_MPROTECT'];
+begin
+  Fpmprotect:=do_syscall(syscall_nr_mprotect,TSysParam(adr),TSysParam(len),TSysParam(prot));
+end;
+
 {
 {
   Interface to Unix ioctl call.
   Interface to Unix ioctl call.
   Performs various operations on the filedescriptor Handle.
   Performs various operations on the filedescriptor Handle.

+ 1 - 0
rtl/msdos/dos.pp

@@ -316,6 +316,7 @@ end;
 procedure setverify(verify : boolean);
 procedure setverify(verify : boolean);
 begin
 begin
   dosregs.ah:=$2e;
   dosregs.ah:=$2e;
+  dosregs.dl:=0;
   dosregs.al:=ord(verify);
   dosregs.al:=ord(verify);
   msdos(dosregs);
   msdos(dosregs);
 end;
 end;

+ 23 - 18
rtl/objpas/classes/classesh.inc

@@ -602,11 +602,14 @@ type
   end;
   end;
 
 
 { TStrings class }
 { TStrings class }
+  TMissingNameValueSeparatorAction = (mnvaValue,mnvaName,mnvaEmpty,mnvaError);
+  TMissingNameValueSeparatorActions = set of TMissingNameValueSeparatorAction;
 
 
   TStrings = class(TPersistent)
   TStrings = class(TPersistent)
   private
   private
     FDefaultEncoding: TEncoding;
     FDefaultEncoding: TEncoding;
     FEncoding: TEncoding;
     FEncoding: TEncoding;
+    FMissingNameValueSeparatorAction: TMissingNameValueSeparatorAction;
     FSpecialCharsInited : boolean;
     FSpecialCharsInited : boolean;
     FAlwaysQuote: Boolean;
     FAlwaysQuote: Boolean;
     FQuoteChar : Char;
     FQuoteChar : Char;
@@ -620,6 +623,7 @@ type
     FLineBreak : String;
     FLineBreak : String;
     FWriteBOM: Boolean;
     FWriteBOM: Boolean;
     function GetCommaText: string;
     function GetCommaText: string;
+    function GetMissingNameValueSeparatorAction: TMissingNameValueSeparatorAction;
     function GetName(Index: Integer): string;
     function GetName(Index: Integer): string;
     function GetValue(const Name: string): string;
     function GetValue(const Name: string): string;
     Function GetLBS : TTextLineBreakStyle;
     Function GetLBS : TTextLineBreakStyle;
@@ -628,6 +632,7 @@ type
     Procedure SetLBS (AValue : TTextLineBreakStyle);
     Procedure SetLBS (AValue : TTextLineBreakStyle);
     procedure ReadData(Reader: TReader);
     procedure ReadData(Reader: TReader);
     procedure SetCommaText(const Value: string);
     procedure SetCommaText(const Value: string);
+    procedure SetMissingNameValueSeparatorAction(AValue: TMissingNameValueSeparatorAction);
     procedure SetStringsAdapter(const Value: IStringsAdapter);
     procedure SetStringsAdapter(const Value: IStringsAdapter);
     procedure SetValue(const Name, Value: string);
     procedure SetValue(const Name, Value: string);
     procedure SetDelimiter(c:Char);
     procedure SetDelimiter(c:Char);
@@ -678,12 +683,12 @@ type
     function AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer; overload;
     function AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer; overload;
     function AddPair(const AName, AValue: string): TStrings; overload; {$IFDEF CLASSESINLINE}inline;{$ENDIF}
     function AddPair(const AName, AValue: string): TStrings; overload; {$IFDEF CLASSESINLINE}inline;{$ENDIF}
     function AddPair(const AName, AValue: string; AObject: TObject): TStrings; overload;
     function AddPair(const AName, AValue: string; AObject: TObject): TStrings; overload;
-    procedure Append(const S: string);
     procedure AddStrings(TheStrings: TStrings); overload; virtual;
     procedure AddStrings(TheStrings: TStrings); overload; virtual;
     procedure AddStrings(TheStrings: TStrings; ClearFirst : Boolean); overload;
     procedure AddStrings(TheStrings: TStrings; ClearFirst : Boolean); overload;
     procedure AddStrings(const TheStrings: array of string); overload; virtual;
     procedure AddStrings(const TheStrings: array of string); overload; virtual;
     procedure AddStrings(const TheStrings: array of string; ClearFirst : Boolean); overload;
     procedure AddStrings(const TheStrings: array of string; ClearFirst : Boolean); overload;
     Procedure AddText(Const S : String); virtual;
     Procedure AddText(Const S : String); virtual;
+    procedure Append(const S: string);
     procedure Assign(Source: TPersistent); override;
     procedure Assign(Source: TPersistent); override;
     procedure BeginUpdate;
     procedure BeginUpdate;
     procedure Clear; virtual; abstract;
     procedure Clear; virtual; abstract;
@@ -692,14 +697,15 @@ type
     function Equals(Obj: TObject): Boolean; override; overload;
     function Equals(Obj: TObject): Boolean; override; overload;
     function Equals(TheStrings: TStrings): Boolean; overload;
     function Equals(TheStrings: TStrings): Boolean; overload;
     procedure Exchange(Index1, Index2: Integer); virtual;
     procedure Exchange(Index1, Index2: Integer); virtual;
+    function  ExtractName(Const S:String):String;
     function GetEnumerator: TStringsEnumerator;
     function GetEnumerator: TStringsEnumerator;
+    procedure GetNameValue(Index : Integer; Out AName,AValue : String);
     function GetText: PChar; virtual;
     function GetText: PChar; virtual;
     function IndexOf(const S: string): Integer; virtual;
     function IndexOf(const S: string): Integer; virtual;
     function IndexOfName(const Name: string): Integer; virtual;
     function IndexOfName(const Name: string): Integer; virtual;
     function IndexOfObject(AObject: TObject): Integer; virtual;
     function IndexOfObject(AObject: TObject): Integer; virtual;
     procedure Insert(Index: Integer; const S: string); virtual; abstract;
     procedure Insert(Index: Integer; const S: string); virtual; abstract;
-    procedure InsertObject(Index: Integer; const S: string;
-      AObject: TObject);
+    procedure InsertObject(Index: Integer; const S: string; AObject: TObject);
     procedure LoadFromFile(const FileName: string); overload; virtual;
     procedure LoadFromFile(const FileName: string); overload; virtual;
     procedure LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
     procedure LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
     procedure LoadFromFile(const FileName: string; AEncoding: TEncoding); overload; virtual;
     procedure LoadFromFile(const FileName: string; AEncoding: TEncoding); overload; virtual;
@@ -712,29 +718,28 @@ type
     procedure SaveToStream(Stream: TStream); overload; virtual;
     procedure SaveToStream(Stream: TStream); overload; virtual;
     procedure SaveToStream(Stream: TStream; AEncoding: TEncoding); overload; virtual;
     procedure SaveToStream(Stream: TStream; AEncoding: TEncoding); overload; virtual;
     procedure SetText(TheText: PChar); virtual;
     procedure SetText(TheText: PChar); virtual;
-    procedure GetNameValue(Index : Integer; Out AName,AValue : String);
-    function  ExtractName(Const S:String):String;
-    Property TextLineBreakStyle : TTextLineBreakStyle Read GetLBS Write SetLBS;
-    property Delimiter: Char read GetDelimiter write SetDelimiter;
-    property DelimitedText: string read GetDelimitedText write SetDelimitedText;
-    property DefaultEncoding: TEncoding read FDefaultEncoding write SetDefaultEncoding;
-    property Encoding: TEncoding read FEncoding;
-    property LineBreak : string Read GetLineBreak write SetLineBreak;
-    Property StrictDelimiter : Boolean Read FStrictDelimiter Write FStrictDelimiter;
     property AlwaysQuote: Boolean read FAlwaysQuote write FAlwaysQuote;
     property AlwaysQuote: Boolean read FAlwaysQuote write FAlwaysQuote;
-    property QuoteChar: Char read GetQuoteChar write SetQuoteChar;
-    Property NameValueSeparator : Char Read GetNameValueSeparator Write SetNameValueSeparator;
-    property ValueFromIndex[Index: Integer]: string read GetValueFromIndex write SetValueFromIndex;
     property Capacity: Integer read GetCapacity write SetCapacity;
     property Capacity: Integer read GetCapacity write SetCapacity;
     property CommaText: string read GetCommaText write SetCommaText;
     property CommaText: string read GetCommaText write SetCommaText;
     property Count: Integer read GetCount;
     property Count: Integer read GetCount;
+    property DefaultEncoding: TEncoding read FDefaultEncoding write SetDefaultEncoding;
+    property DelimitedText: string read GetDelimitedText write SetDelimitedText;
+    property Delimiter: Char read GetDelimiter write SetDelimiter;
+    property Encoding: TEncoding read FEncoding;
+    property LineBreak : string Read GetLineBreak write SetLineBreak;
+    Property MissingNameValueSeparatorAction : TMissingNameValueSeparatorAction Read GetMissingNameValueSeparatorAction Write SetMissingNameValueSeparatorAction;
     property Names[Index: Integer]: string read GetName;
     property Names[Index: Integer]: string read GetName;
+    Property NameValueSeparator : Char Read GetNameValueSeparator Write SetNameValueSeparator;
     property Objects[Index: Integer]: TObject read GetObject write PutObject;
     property Objects[Index: Integer]: TObject read GetObject write PutObject;
-    property Values[const Name: string]: string read GetValue write SetValue;
+    property QuoteChar: Char read GetQuoteChar write SetQuoteChar;
+    Property SkipLastLineBreak : Boolean Read GetSkipLastLineBreak Write SetSkipLastLineBreak;
+    Property StrictDelimiter : Boolean Read FStrictDelimiter Write FStrictDelimiter;
     property Strings[Index: Integer]: string read Get write Put; default;
     property Strings[Index: Integer]: string read Get write Put; default;
-    property Text: string read GetTextStr write SetTextStr;
     property StringsAdapter: IStringsAdapter read FAdapter write SetStringsAdapter;
     property StringsAdapter: IStringsAdapter read FAdapter write SetStringsAdapter;
-    Property SkipLastLineBreak : Boolean Read GetSkipLastLineBreak Write SetSkipLastLineBreak;
+    property Text: string read GetTextStr write SetTextStr;
+    Property TextLineBreakStyle : TTextLineBreakStyle Read GetLBS Write SetLBS;
+    property ValueFromIndex[Index: Integer]: string read GetValueFromIndex write SetValueFromIndex;
+    property Values[const Name: string]: string read GetValue write SetValue;
     property WriteBOM: Boolean read FWriteBOM write FWriteBOM;
     property WriteBOM: Boolean read FWriteBOM write FWriteBOM;
   end;
   end;
 
 

+ 26 - 1
rtl/objpas/classes/stringl.inc

@@ -162,6 +162,7 @@ begin
   FNameValueSeparator:=c;
   FNameValueSeparator:=c;
 end;
 end;
 
 
+
 Function TStrings.GetNameValueSeparator :Char;
 Function TStrings.GetNameValueSeparator :Char;
 begin
 begin
   CheckSpecialChars;
   CheckSpecialChars;
@@ -192,6 +193,12 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TStrings.GetMissingNameValueSeparatorAction: TMissingNameValueSeparatorAction;
+begin
+  CheckSpecialChars;
+  Result:=FMissingNameValueSeparatorAction;
+end;
+
 
 
 Function TStrings.GetDelimitedText: string;
 Function TStrings.GetDelimitedText: string;
 
 
@@ -240,6 +247,7 @@ procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
 Var L : longint;
 Var L : longint;
 
 
 begin
 begin
+  aName:='';
   CheckSpecialChars;
   CheckSpecialChars;
   AValue:=Strings[Index];
   AValue:=Strings[Index];
   L:=Pos(FNameValueSeparator,AValue);
   L:=Pos(FNameValueSeparator,AValue);
@@ -249,7 +257,18 @@ begin
     System.Delete(AValue,1,L);
     System.Delete(AValue,1,L);
     end
     end
   else
   else
-    AName:='';
+    case FMissingNameValueSeparatorAction of
+      mnvaValue : ;
+      mnvaName :
+        begin
+        aName:=aValue;
+        aValue:='';
+        end;
+      mnvaEmpty :
+        aValue:='';
+      mnvaError :
+        Raise EStringListError.CreateFmt(SErrNoNameValuePairAt,[Index]);
+    end;
 end;
 end;
 
 
 function TStrings.ExtractName(const s:String):String;
 function TStrings.ExtractName(const s:String):String;
@@ -445,6 +464,12 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TStrings.SetMissingNameValueSeparatorAction(AValue: TMissingNameValueSeparatorAction);
+begin
+  CheckSpecialChars;
+  FMissingNameValueSeparatorAction:=aValue;
+end;
+
 
 
 Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
 Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
 
 

+ 1 - 0
rtl/objpas/rtlconst.inc

@@ -308,6 +308,7 @@ ResourceString
   SParamIsNegative              = 'Parameter "%s" cannot be negative.';
   SParamIsNegative              = 'Parameter "%s" cannot be negative.';
   SErrCannotWriteToProperty     = 'Cannot write to property "%s".';
   SErrCannotWriteToProperty     = 'Cannot write to property "%s".';
   SErrCannotReadProperty        = 'Cannot read property "%s".';
   SErrCannotReadProperty        = 'Cannot read property "%s".';
+  SErrNoNameValuePairAt         = 'No name=value pair at position %d.';
 
 
 { ---------------------------------------------------------------------
 { ---------------------------------------------------------------------
     Keysim Names
     Keysim Names

+ 12 - 12
rtl/objpas/sysutils/syshelp.inc

@@ -1097,34 +1097,34 @@ end;
 
 
 function TStringHelper.Split(const Separators: array of Char): TStringArray;
 function TStringHelper.Split(const Separators: array of Char): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,#0,#0,Length,TStringSplitOptions.None);
+  Result:=Split(Separators,#0,#0,Length+1,TStringSplitOptions.None);
 end;
 end;
 
 
 
 
 function TStringHelper.Split(const Separators: array of Char; ACount: SizeInt
 function TStringHelper.Split(const Separators: array of Char; ACount: SizeInt
   ): TStringArray;
   ): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,#0,#0,ACount,TStringSplitOptions.None);
+  Result:=Split(Separators,#0,#0,ACount,TStringSplitOptions.None);
 end;
 end;
 
 
 
 
 function TStringHelper.Split(const Separators: array of Char;
 function TStringHelper.Split(const Separators: array of Char;
   Options: TStringSplitOptions): TStringArray;
   Options: TStringSplitOptions): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,Length,Options);
+  Result:=Split(Separators,Length+1,Options);
 end;
 end;
 
 
 
 
 function TStringHelper.Split(const Separators: array of Char; ACount: SizeInt;
 function TStringHelper.Split(const Separators: array of Char; ACount: SizeInt;
   Options: TStringSplitOptions): TStringArray;
   Options: TStringSplitOptions): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,#0,#0,ACount,Options);
+  Result:=Split(Separators,#0,#0,ACount,Options);
 end;
 end;
 
 
 
 
 function TStringHelper.Split(const Separators: array of string): TStringArray;
 function TStringHelper.Split(const Separators: array of string): TStringArray;
 begin
 begin
-  Result:=Split(Separators,Length);
+  Result:=Split(Separators,Length+1);
 end;
 end;
 
 
 
 
@@ -1138,7 +1138,7 @@ end;
 function TStringHelper.Split(const Separators: array of string;
 function TStringHelper.Split(const Separators: array of string;
   Options: TStringSplitOptions): TStringArray;
   Options: TStringSplitOptions): TStringArray;
 begin
 begin
-  Result:=Split(Separators,Length,Options);
+  Result:=Split(Separators,Length+1,Options);
 end;
 end;
 
 
 
 
@@ -1166,7 +1166,7 @@ end;
 function TStringHelper.Split(const Separators: array of Char; AQuoteStart,
 function TStringHelper.Split(const Separators: array of Char; AQuoteStart,
   AQuoteEnd: Char; Options: TStringSplitOptions): TStringArray;
   AQuoteEnd: Char; Options: TStringSplitOptions): TStringArray;
 begin
 begin
-  Result:=Split(Separators,AQuoteStart,AQuoteEnd,Length,Options);
+  Result:=Split(Separators,AQuoteStart,AQuoteEnd,Length+1,Options);
 end;
 end;
 
 
 
 
@@ -1211,7 +1211,7 @@ begin
   While (Sep<>-1) and ((ACount=0) or (Len<ACount)) do
   While (Sep<>-1) and ((ACount=0) or (Len<ACount)) do
     begin
     begin
     T:=SubString(LastSep,Sep-LastSep);
     T:=SubString(LastSep,Sep-LastSep);
-//    Writeln('Examining >',T,'< at pos,',LastSep,' till pos ',Sep);
+//    Writeln('Examining >',T,'< at pos ',LastSep,', till pos ',Sep);
     If (T<>'') or (not (TStringSplitOptions.ExcludeEmpty=Options)) then
     If (T<>'') or (not (TStringSplitOptions.ExcludeEmpty=Options)) then
       begin
       begin
       MaybeGrow(Len);
       MaybeGrow(Len);
@@ -1221,7 +1221,7 @@ begin
     LastSep:=Sep+1;
     LastSep:=Sep+1;
     Sep:=NextSep(LastSep);
     Sep:=NextSep(LastSep);
     end;
     end;
-  if (LastSep<Length) and ((ACount=0) or (Len<ACount)) then
+  if (LastSep<=Length) and ((ACount=0) or (Len<ACount)) then
     begin
     begin
     T:=SubString(LastSep);
     T:=SubString(LastSep);
 //    Writeln('Examining >',T,'< at pos,',LastSep,' till pos ',Sep);
 //    Writeln('Examining >',T,'< at pos,',LastSep,' till pos ',Sep);
@@ -1243,14 +1243,14 @@ end;
 function TStringHelper.Split(const Separators: array of string; AQuoteStart,
 function TStringHelper.Split(const Separators: array of string; AQuoteStart,
   AQuoteEnd: Char): TStringArray;
   AQuoteEnd: Char): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,AQuoteStart,AQuoteEnd,Length,TStringSplitOptions.None);
+  Result:=SPlit(Separators,AQuoteStart,AQuoteEnd,Length+1,TStringSplitOptions.None);
 end;
 end;
 
 
 
 
 function TStringHelper.Split(const Separators: array of string; AQuoteStart,
 function TStringHelper.Split(const Separators: array of string; AQuoteStart,
   AQuoteEnd: Char; Options: TStringSplitOptions): TStringArray;
   AQuoteEnd: Char; Options: TStringSplitOptions): TStringArray;
 begin
 begin
-  Result:=SPlit(Separators,AQuoteStart,AQuoteEnd,Length,Options);
+  Result:=SPlit(Separators,AQuoteStart,AQuoteEnd,Length+1,Options);
 end;
 end;
 
 
 
 
@@ -1304,7 +1304,7 @@ begin
     LastSep:=Sep+System.Length(Separators[Match]);
     LastSep:=Sep+System.Length(Separators[Match]);
     Sep:=NextSep(LastSep,Match);
     Sep:=NextSep(LastSep,Match);
     end;
     end;
-  if (LastSep<Length) and ((ACount=0) or (Len<ACount)) then
+  if (LastSep<=Length) and ((ACount=0) or (Len<ACount)) then
     begin
     begin
     T:=SubString(LastSep);
     T:=SubString(LastSep);
 //    Writeln('Examining >',T,'< at pos,',LastSep,' till pos ',Sep);
 //    Writeln('Examining >',T,'< at pos,',LastSep,' till pos ',Sep);

+ 5 - 2
rtl/openbsd/i386/si_c.inc

@@ -18,6 +18,7 @@
 
 
 procedure __init; cdecl; external name '__init';
 procedure __init; cdecl; external name '__init';
 procedure c_exit(exit_code: cint); cdecl; noreturn; external name 'exit';
 procedure c_exit(exit_code: cint); cdecl; noreturn; external name 'exit';
+function _csu_finish(_argv: PPChar; _envp: PPChar; _cleanup: TCdeclProcedure): PPPChar; cdecl; external name '_csu_finish';
 
 
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl; forward;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl; forward;
 
 
@@ -41,9 +42,11 @@ function _strrchr(str: PChar; character: LongInt): PChar; forward;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl;
   var
   var
     I: SizeUInt;
     I: SizeUInt;
+    environp: PPPChar;
   begin
   begin
-    environ:=envp;
-    operatingsystem_parameter_envp:=envp;
+    environp:=_csu_finish(argv, envp, cleanup);
+    environ:=environp^;
+    operatingsystem_parameter_envp:=environ;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=argv;
     operatingsystem_parameter_argv:=argv;
     if argv[0]<>nil then
     if argv[0]<>nil then

+ 5 - 2
rtl/openbsd/i386/si_g.inc

@@ -25,6 +25,7 @@ function atexit(proc: TCdeclProcedure): cint; cdecl; external name 'atexit';
 procedure _monstartup(lowpc, highpc: u_long); cdecl; external name '_monstartup';
 procedure _monstartup(lowpc, highpc: u_long); cdecl; external name '_monstartup';
 procedure __init; cdecl; external name '__init';
 procedure __init; cdecl; external name '__init';
 procedure c_exit(exit_code: cint); cdecl; noreturn; external name 'exit';
 procedure c_exit(exit_code: cint); cdecl; noreturn; external name 'exit';
+function _csu_finish(_argv: PPChar; _envp: PPChar; _cleanup: TCdeclProcedure): PPPChar; cdecl; external name '_csu_finish';
 
 
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl; forward;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl; forward;
 
 
@@ -48,9 +49,11 @@ function _strrchr(str: PChar; character: LongInt): PChar; forward;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl;
 procedure _FPC_proc___start(argc: LongInt; argv: PPChar; envp: Pointer; cleanup: TCdeclProcedure); cdecl;
   var
   var
     I: SizeUInt;
     I: SizeUInt;
+    environp: PPPChar;
   begin
   begin
-    environ:=envp;
-    operatingsystem_parameter_envp:=envp;
+    environp:=_csu_finish(argv, envp, cleanup);
+    environ:=environp^;
+    operatingsystem_parameter_envp:=environ;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argc:=argc;
     operatingsystem_parameter_argv:=argv;
     operatingsystem_parameter_argv:=argv;
     if argv[0]<>nil then
     if argv[0]<>nil then

+ 1 - 0
rtl/unix/bunxh.inc

@@ -106,6 +106,7 @@ Type TGrpArr = Array [0..0] of TGid;            { C style array workarounds}
     Function  fpSetPriority(Which,Who,What:cint):cint;
     Function  fpSetPriority(Which,Who,What:cint):cint;
     Function  Fpmmap(start:pointer;len:size_t;prot:cint;flags:cint;fd:cint;offst:off_t):pointer; external name 'FPC_SYSC_MMAP';
     Function  Fpmmap(start:pointer;len:size_t;prot:cint;flags:cint;fd:cint;offst:off_t):pointer; external name 'FPC_SYSC_MMAP';
     Function  Fpmunmap(start:pointer;len:size_t):cint;  external name 'FPC_SYSC_MUNMAP';
     Function  Fpmunmap(start:pointer;len:size_t):cint;  external name 'FPC_SYSC_MUNMAP';
+    Function  Fpmprotect(start:pointer;len:size_t;prot:cint):cint; external name 'FPC_SYSC_MPROTECT';
 
 
     Function  FpGetEnv (name : pChar): pChar; external name 'FPC_SYSC_FPGETENVPCHAR';
     Function  FpGetEnv (name : pChar): pChar; external name 'FPC_SYSC_FPGETENVPCHAR';
     function  fpsettimeofday(tp:ptimeval;tzp:ptimezone):cint;
     function  fpsettimeofday(tp:ptimeval;tzp:ptimezone):cint;

+ 1 - 0
rtl/unix/oscdeclh.inc

@@ -156,6 +156,7 @@ const
     Function  fpSetPriority (Which,Who,What:cint):cint; cdecl; external clib name 'setpriority';
     Function  fpSetPriority (Which,Who,What:cint):cint; cdecl; external clib name 'setpriority';
     function  fpmmap    (addr:pointer;len:size_t;prot:cint;flags:cint;fd:cint;ofs:off_t):pointer; cdecl; external clib name 'mmap'+suffix64bit;
     function  fpmmap    (addr:pointer;len:size_t;prot:cint;flags:cint;fd:cint;ofs:off_t):pointer; cdecl; external clib name 'mmap'+suffix64bit;
     function  fpmunmap  (addr:pointer;len:size_t):cint; cdecl; external clib name 'munmap';
     function  fpmunmap  (addr:pointer;len:size_t):cint; cdecl; external clib name 'munmap';
+    function  fpmprotect(addr:pointer;len:size_t;prot:cint):cint; cdecl; external clib name 'mprotect';
 
 
     function  fpgetenv  (name : pchar):pchar; cdecl; external clib name 'getenv';
     function  fpgetenv  (name : pchar):pchar; cdecl; external clib name 'getenv';
 {$ifndef beos}
 {$ifndef beos}

BIN
tests/test/cg/obj/haiku/x86_64/cpptcl1.o


BIN
tests/test/cg/obj/haiku/x86_64/cpptcl2.o


BIN
tests/test/cg/obj/haiku/x86_64/ctest.o


BIN
tests/test/cg/obj/haiku/x86_64/tcext3.o


BIN
tests/test/cg/obj/haiku/x86_64/tcext4.o


BIN
tests/test/cg/obj/haiku/x86_64/tcext5.o


BIN
tests/test/cg/obj/haiku/x86_64/tcext6.o


+ 1 - 0
tests/test/cg/obj/readme.txt

@@ -44,6 +44,7 @@ Android-mipsel : GCC 4.7
 Android-aarch64 : GCC 4.9
 Android-aarch64 : GCC 4.9
 Android-x86_64 : GCC 4.9
 Android-x86_64 : GCC 4.9
 haiku-i386 : gcc 2.95.3-haiku-100818
 haiku-i386 : gcc 2.95.3-haiku-100818
+haiku-x86_64 : gcc version 7.3.0 (2018_05_01)
 aix-powerpc64 : gcc (GCC) 4.8.1 using "gcc -maix64" for TEST_CCOMPILER
 aix-powerpc64 : gcc (GCC) 4.8.1 using "gcc -maix64" for TEST_CCOMPILER
                 on (AIX power-aix 1 7 00F84C0C4C00)
                 on (AIX power-aix 1 7 00F84C0C4C00)
 OS/2 (os2-i386): original EMX port of GCC (GCC 2.8.1) except for tcext6.c which
 OS/2 (os2-i386): original EMX port of GCC (GCC 2.8.1) except for tcext6.c which

+ 223 - 0
tests/test/cpu16/i8086/tfarcal2.pp

@@ -12,6 +12,11 @@
 
 
 program tfarcal2;
 program tfarcal2;
 
 
+{$ifdef FPC}
+{ FPC needs $goto on to accept labels and gotos }
+{$goto on}
+{$endif}
+
 uses
 uses
   dos;
   dos;
 
 
@@ -24,9 +29,16 @@ const
   NearInt = $E7;
   NearInt = $E7;
   FarInt = $E8;
   FarInt = $E8;
 
 
+  NoSegOverride = 0;
+  SegOverrideCS = $2E;
+  SegOverrideSS = $36;
+  SegOverrideDS = $3E;
+  SegOverrideES = $26;
+
 var
 var
   OldNearIntVec: FarPointer;
   OldNearIntVec: FarPointer;
   OldFarIntVec: FarPointer;
   OldFarIntVec: FarPointer;
+  ExpectSegOverride: Byte;
 
 
 procedure Error;
 procedure Error;
 begin
 begin
@@ -40,6 +52,12 @@ procedure IntNearHandler(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP: Word
 var
 var
   modrm: Byte;
   modrm: Byte;
 begin
 begin
+  if ExpectSegOverride <> 0 then
+  begin
+    if Mem[CS:IP]<>ExpectSegOverride then
+      Error;
+    Inc(IP);
+  end;
   if Mem[CS:IP]<>$FF then
   if Mem[CS:IP]<>$FF then
     Error;
     Error;
   Inc(IP);
   Inc(IP);
@@ -64,6 +82,12 @@ procedure IntFarHandler(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP: Word)
 var
 var
   modrm: Byte;
   modrm: Byte;
 begin
 begin
+  if ExpectSegOverride <> 0 then
+  begin
+    if Mem[CS:IP]<>ExpectSegOverride then
+      Error;
+    Inc(IP);
+  end;
   if Mem[CS:IP]<>$FF then
   if Mem[CS:IP]<>$FF then
     Error;
     Error;
   Inc(IP);
   Inc(IP);
@@ -115,6 +139,203 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure testlocallabels;
+label
+  local_label2;
+begin
+  ExpectSegOverride := SegOverrideCS;
+  asm
+    jmp @@skip_labels
+
+@@local_label1:
+    db 0, 0, 0, 0
+
+local_label2:
+    db 0, 0, 0, 0
+
+@@skip_labels:
+    int NearInt
+    call word [@@local_label1] { near }
+    int NearInt
+    call word ptr [@@local_label1] { near }
+    int NearInt
+    call word ptr @@local_label1 { near }
+
+    int FarInt
+    call dword [@@local_label1] { far }
+    int FarInt
+    call dword ptr [@@local_label1] { far }
+    int FarInt
+    call dword ptr @@local_label1 { far }
+
+    int NearInt
+    call word [local_label2] { near }
+    int NearInt
+    call word ptr [local_label2] { near }
+    int NearInt
+    call word ptr local_label2 { near }
+
+    int FarInt
+    call dword [local_label2] { far }
+    int FarInt
+    call dword ptr [local_label2] { far }
+    int FarInt
+    call dword ptr local_label2 { far }
+
+    { explicit CS: prefix }
+    int NearInt
+    call word [cs:@@local_label1] { near }
+    int NearInt
+    call word ptr cs:[@@local_label1] { near }
+    int NearInt
+    call word ptr [cs:@@local_label1] { near }
+    int NearInt
+    call word ptr cs:@@local_label1 { near }
+
+    int FarInt
+    call dword [cs:@@local_label1] { far }
+    int FarInt
+    call dword ptr cs:[@@local_label1] { far }
+    int FarInt
+    call dword ptr [cs:@@local_label1] { far }
+    int FarInt
+    call dword ptr cs:@@local_label1 { far }
+
+    int NearInt
+    call word [cs:local_label2] { near }
+    int NearInt
+    call word ptr cs:[local_label2] { near }
+    int NearInt
+    call word ptr [cs:local_label2] { near }
+    int NearInt
+    call word ptr cs:local_label2 { near }
+
+    int FarInt
+    call dword [cs:local_label2] { far }
+    int FarInt
+    call dword ptr cs:[local_label2] { far }
+    int FarInt
+    call dword ptr [cs:local_label2] { far }
+    int FarInt
+    call dword ptr cs:local_label2 { far }
+
+    { explicit DS: prefix }
+    mov byte ptr [ExpectSegOverride], NoSegOverride  { no segment override
+            should be produced, because DS is the default for the processor }
+    int NearInt
+    call word [ds:@@local_label1] { near }
+    int NearInt
+    call word ptr ds:[@@local_label1] { near }
+    int NearInt
+    call word ptr [ds:@@local_label1] { near }
+    int NearInt
+    call word ptr ds:@@local_label1 { near }
+
+    int FarInt
+    call dword [ds:@@local_label1] { far }
+    int FarInt
+    call dword ptr ds:[@@local_label1] { far }
+    int FarInt
+    call dword ptr [ds:@@local_label1] { far }
+    int FarInt
+    call dword ptr ds:@@local_label1 { far }
+
+    int NearInt
+    call word [ds:local_label2] { near }
+    int NearInt
+    call word ptr ds:[local_label2] { near }
+    int NearInt
+    call word ptr [ds:local_label2] { near }
+    int NearInt
+    call word ptr ds:local_label2 { near }
+
+    int FarInt
+    call dword [ds:local_label2] { far }
+    int FarInt
+    call dword ptr ds:[local_label2] { far }
+    int FarInt
+    call dword ptr [ds:local_label2] { far }
+    int FarInt
+    call dword ptr ds:local_label2 { far }
+
+    { explicit ES: prefix }
+    mov byte ptr [ExpectSegOverride], SegOverrideES
+    int NearInt
+    call word [es:@@local_label1] { near }
+    int NearInt
+    call word ptr es:[@@local_label1] { near }
+    int NearInt
+    call word ptr [es:@@local_label1] { near }
+    int NearInt
+    call word ptr es:@@local_label1 { near }
+
+    int FarInt
+    call dword [es:@@local_label1] { far }
+    int FarInt
+    call dword ptr es:[@@local_label1] { far }
+    int FarInt
+    call dword ptr [es:@@local_label1] { far }
+    int FarInt
+    call dword ptr es:@@local_label1 { far }
+
+    int NearInt
+    call word [es:local_label2] { near }
+    int NearInt
+    call word ptr es:[local_label2] { near }
+    int NearInt
+    call word ptr [es:local_label2] { near }
+    int NearInt
+    call word ptr es:local_label2 { near }
+
+    int FarInt
+    call dword [es:local_label2] { far }
+    int FarInt
+    call dword ptr es:[local_label2] { far }
+    int FarInt
+    call dword ptr [es:local_label2] { far }
+    int FarInt
+    call dword ptr es:local_label2 { far }
+
+    { explicit SS: prefix }
+    mov byte ptr [ExpectSegOverride], SegOverrideSS
+    int NearInt
+    call word [ss:@@local_label1] { near }
+    int NearInt
+    call word ptr ss:[@@local_label1] { near }
+    int NearInt
+    call word ptr [ss:@@local_label1] { near }
+    int NearInt
+    call word ptr ss:@@local_label1 { near }
+
+    int FarInt
+    call dword [ss:@@local_label1] { far }
+    int FarInt
+    call dword ptr ss:[@@local_label1] { far }
+    int FarInt
+    call dword ptr [ss:@@local_label1] { far }
+    int FarInt
+    call dword ptr ss:@@local_label1 { far }
+
+    int NearInt
+    call word [ss:local_label2] { near }
+    int NearInt
+    call word ptr ss:[local_label2] { near }
+    int NearInt
+    call word ptr [ss:local_label2] { near }
+    int NearInt
+    call word ptr ss:local_label2 { near }
+
+    int FarInt
+    call dword [ss:local_label2] { far }
+    int FarInt
+    call dword ptr ss:[local_label2] { far }
+    int FarInt
+    call dword ptr [ss:local_label2] { far }
+    int FarInt
+    call dword ptr ss:local_label2 { far }
+  end;
+end;
+
 var
 var
   g16: integer;
   g16: integer;
   g32: longint;
   g32: longint;
@@ -124,6 +345,7 @@ begin
   GetIntVec(FarInt, OldFarIntVec);
   GetIntVec(FarInt, OldFarIntVec);
   SetIntVec(FarInt, Ptr(Seg(IntFarHandler),Ofs(IntFarHandler)));
   SetIntVec(FarInt, Ptr(Seg(IntFarHandler),Ofs(IntFarHandler)));
 
 
+  ExpectSegOverride := 0;
   asm
   asm
     int NearInt
     int NearInt
     call word ptr $1234
     call word ptr $1234
@@ -202,6 +424,7 @@ begin
 {$endif FPC}
 {$endif FPC}
   end;
   end;
   testloc(5, 10);
   testloc(5, 10);
+  testlocallabels;
   Writeln('Ok');
   Writeln('Ok');
 
 
   SetIntVec(NearInt, OldNearIntVec);
   SetIntVec(NearInt, OldNearIntVec);

+ 19 - 0
tests/webtbs/tw35272.pp

@@ -0,0 +1,19 @@
+var
+  b1, b2, b3: longbool;
+begin
+  b1:=longbool(1);
+  b2:=longbool(2);
+  b3:=b1 and b2;
+  if not b3 then
+    halt(1);
+  b3:=b1 xor b2;
+  if b3 then
+    halt(2);
+{$b+}
+  b3:=b1 and b2;
+  if not b3 then
+    halt(3);
+  b3:=b1 xor b2;
+  if b3 then
+    halt(4);
+end.

+ 30 - 27
utils/fpdoc/dw_htmlchm.inc

@@ -192,12 +192,12 @@ begin
         // by unit
         // by unit
         TmpItem := ObjUnitItem.Children.NewItem;
         TmpItem := ObjUnitItem.Children.NewItem;
         TmpItem.Text := Element.Name;
         TmpItem.Text := Element.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
         
         
         //alpha
         //alpha
         TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
         TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
         TmpItem.Text := Element.Name;
         TmpItem.Text := Element.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
         
         
       end;
       end;
       
       
@@ -208,12 +208,12 @@ begin
         // by unit
         // by unit
         TmpItem := RoutinesUnitItem.Children.NewItem;
         TmpItem := RoutinesUnitItem.Children.NewItem;
         TmpItem.Text := Element.Name;
         TmpItem.Text := Element.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
         
         
         // alpha
         // alpha
         TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
         TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
         TmpItem.Text := Element.Name;
         TmpItem.Text := Element.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
       end;
       end;
     end;
     end;
   end;
   end;
@@ -289,7 +289,7 @@ var
   ParentElement: TPasElement;
   ParentElement: TPasElement;
   MemberItem: TChmSiteMapItem;
   MemberItem: TChmSiteMapItem;
   Stream: TMemoryStream;
   Stream: TMemoryStream;
-  s: String;
+  RedirectUrl,Urls: String;
 
 
 begin
 begin
   DoLog('Generating Index...');
   DoLog('Generating Index...');
@@ -305,7 +305,7 @@ begin
         continue;
         continue;
       ParentItem := Index.Items.NewItem;
       ParentItem := Index.Items.NewItem;
       ParentItem.Text := AModule.Name;
       ParentItem.Text := AModule.Name;
-      ParentItem.Local := FixHTMLpath(Allocator.GetFilename(AModule, 0));
+      ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(AModule, 0)));
 
 
       //  classes
       //  classes
       for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
       for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
@@ -313,18 +313,27 @@ begin
         ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
         ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
         ParentItem := Index.Items.NewItem;
         ParentItem := Index.Items.NewItem;
         ParentItem.Text := ParentELement.Name;
         ParentItem.Text := ParentELement.Name;
-        ParentItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
+        ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
         for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
         for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
         begin
         begin
           TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
           TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
-          if TmpElement is TPasEnumValue then
-             s := UTF8Encode(ResolveLinkIDAbs(tmpElement.Parent.PathName))
-           else
-             s := UTF8Encode(ResolveLinkIDAbs(tmpElement.PathName));
-           if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
+          if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
             continue;
             continue;
           if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
           if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
             continue;
             continue;
+          Urls:=FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
+          RedirectUrl:='';
+          if TmpElement is TPasEnumValue then
+             RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.Parent.PathName))
+           else
+             RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.PathName));
+
+          if(trim(RedirectUrl)<>'') and (RedirectUrl<>urls) then
+            begin
+              writeln('Hint: Index Resolved:',urls,' to ',RedirectUrl);
+              urls:=RedirectUrl;
+            end;
+
           TmpItem := ParentItem.Children.NewItem;
           TmpItem := ParentItem.Children.NewItem;
           case ElementType(TmpElement) of
           case ElementType(TmpElement) of
             cmtProcedure   : TmpItem.Text := TmpElement.Name + ' procedure';
             cmtProcedure   : TmpItem.Text := TmpElement.Name + ' procedure';
@@ -336,13 +345,7 @@ begin
             cmtInterface   : TmpItem.Text := TmpElement.Name + ' interface';
             cmtInterface   : TmpItem.Text := TmpElement.Name + ' interface';
             cmtUnknown     : TmpItem.Text := TmpElement.Name;
             cmtUnknown     : TmpItem.Text := TmpElement.Name;
           end;
           end;
-          TmpItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
-          if (trim(s)<>'') and (tmpitem.local<>s) then
-            begin
-              writeln('Hint: Index: Resolved:',tmpitem.local,' to ',s);
-              tmpitem.local:=s;
-            end;
-
+          TmpItem.addLocal(Urls);
           {
           {
           ParentElement = Class
           ParentElement = Class
              TmpElement = Member
              TmpElement = Member
@@ -350,11 +353,11 @@ begin
           MemberItem := nil;
           MemberItem := nil;
           MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
           MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
           // ahh! if MemberItem.Local is empty MemberType is not shown!
           // ahh! if MemberItem.Local is empty MemberType is not shown!
-          MemberItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
+          MemberItem.addLocal(Urls);
 
 
           TmpItem := MemberItem.Children.NewItem;
           TmpItem := MemberItem.Children.NewItem;
           TmpItem.Text := ParentElement.Name;
           TmpItem.Text := ParentElement.Name;
-          TmpITem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
+          TmpItem.AddLocal(Urls);
         end;
         end;
       end;
       end;
       // routines
       // routines
@@ -363,7 +366,7 @@ begin
         ParentElement := TPasProcedureType(AModule.InterfaceSection.Functions[j]);
         ParentElement := TPasProcedureType(AModule.InterfaceSection.Functions[j]);
         TmpItem := Index.Items.NewItem;
         TmpItem := Index.Items.NewItem;
         TmpItem.Text := ParentElement.Name + ' ' + ParentElement.ElementTypeName;
         TmpItem.Text := ParentElement.Name + ' ' + ParentElement.ElementTypeName;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
       end;
       end;
       // consts
       // consts
       for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
       for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
@@ -371,7 +374,7 @@ begin
         ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
         ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
         TmpItem := Index.Items.NewItem;
         TmpItem := Index.Items.NewItem;
         TmpItem.Text := ParentElement.Name;
         TmpItem.Text := ParentElement.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
       end;
       end;
       // types
       // types
       for j := 0 to AModule.InterfaceSection.Types.Count-1 do
       for j := 0 to AModule.InterfaceSection.Types.Count-1 do
@@ -379,7 +382,7 @@ begin
         ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
         ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
         TmpItem := Index.Items.NewItem;
         TmpItem := Index.Items.NewItem;
         TmpItem.Text := ParentElement.Name;
         TmpItem.Text := ParentElement.Name;
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
         // enums
         // enums
         if ParentELement is TPasEnumType then
         if ParentELement is TPasEnumType then
         begin
         begin
@@ -390,11 +393,11 @@ begin
             // subitem
             // subitem
             TmpItem := ParentItem.Children.NewItem;
             TmpItem := ParentItem.Children.NewItem;
             TmpItem.Text := TmpElement.Name;
             TmpItem.Text := TmpElement.Name;
-            TmpItem.Local := ParentItem.Local;
+            TmpItem.addLocal(ParentItem.Local);
             // root level
             // root level
             TmpItem := Index.Items.NewItem;
             TmpItem := Index.Items.NewItem;
             TmpItem.Text := TmpElement.Name;
             TmpItem.Text := TmpElement.Name;
-            TmpItem.Local := ParentItem.Local;
+            TmpItem.addLocal(ParentItem.Local);
           end;
           end;
         end;
         end;
       end;
       end;
@@ -404,7 +407,7 @@ begin
         ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
         ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
         TmpItem := Index.Items.NewItem;
         TmpItem := Index.Items.NewItem;
         TmpItem.Text := ParentElement.Name + ' var';
         TmpItem.Text := ParentElement.Name + ' var';
-        TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
+        TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
       end;
       end;
       // declarations
       // declarations
       {
       {

+ 0 - 1
utils/fpdoc/fpdocxmlopts.pas

@@ -389,7 +389,6 @@ begin
     Result:=TMemoryStream.Create;
     Result:=TMemoryStream.Create;
     P.ParseStream(F,Result);
     P.ParseStream(F,Result);
     Result.Position:=0;
     Result.Position:=0;
-    TMemoryStream(Result).SaveToFile('/tmp/opts.xml');
   finally
   finally
     FreeAndNil(F);
     FreeAndNil(F);
     FreeAndNil(P);
     FreeAndNil(P);