Forráskód Böngészése

Merged revisions 8943-8944,8950,8986,8992,8998,9000-9006,9011-9012,9021,9025,9033,9035,9059,9074,9076-9082,9084,9086,9088-9090,9096,9108,9114-9115,9121,9123,9126,9132-9133,9168,9183,9185-9186,9211,9215,9217,9233,9236-9238,9240,9247,9255-9260,9262,9266,9269-9272,9276-9278,9282,9284-9285,9295,9305-9308,9310,9314,9322,9337,9340,9343-9344,9355,9359,9373-9375,9387,9396,9399,9401-9402,9434,9450-9456,9459-9463,9466,9468-9469,9472-9473,9476-9477,9480,9491-9492,9529,9536,9550,9566-9568,9571,9573,9576-9577,9579,9583,9587,9632-9637,9654-9656,9658,9688 via svnmerge from
http://svn.freepascal.org/svn/fpc/trunk

........
r8943 | peter | 2007-10-26 01:10:36 +0200 (Fri, 26 Oct 2007) | 2 lines

* initial code for bootstrapping using only source dirs
........
r8944 | peter | 2007-10-26 10:13:24 +0200 (Fri, 26 Oct 2007) | 2 lines

* compile fixed
........
r8986 | peter | 2007-10-29 10:03:13 +0100 (Mon, 29 Oct 2007) | 2 lines

* depend on fcl-process and paszlib
........
r8992 | peter | 2007-10-29 19:12:40 +0100 (Mon, 29 Oct 2007) | 2 lines

* internal fpmkunit source for bootstrapping
........
r9011 | peter | 2007-10-30 23:07:34 +0100 (Tue, 30 Oct 2007) | 6 lines

* support local and global install directories, default is to use a local
install dir for normal users and for root the global install dir
* updated unit check in fpmake build to look in local and global dirs
* auto bootstrap when fpmkunit is not found, no --bootstrap needed
* archive command line option to call fpmake archive
........
r9012 | Almindor | 2007-10-31 10:08:27 +0100 (Wed, 31 Oct 2007) | 2 lines

* update lnet in fppkg to 0.5.8
........
r9115 | peter | 2007-11-03 21:19:30 +0100 (Sat, 03 Nov 2007) | 2 lines

* debug shows directory/file checks
........
r9121 | peter | 2007-11-03 23:38:47 +0100 (Sat, 03 Nov 2007) | 2 lines

* pass --localunitdir and --globalunitdir to fpmake
........
r9123 | peter | 2007-11-04 00:06:40 +0100 (Sun, 04 Nov 2007) | 2 lines

* install does not a build anymore
........
r9126 | peter | 2007-11-04 00:50:02 +0100 (Sun, 04 Nov 2007) | 2 lines

* updated
........
r9168 | peter | 2007-11-09 02:00:59 +0100 (Fri, 09 Nov 2007) | 3 lines

* compile command added
* basic work for package dependencies
........
r9183 | marco | 2007-11-10 21:34:12 +0100 (Sat, 10 Nov 2007) | 2 lines

* make install was broken, fixes 10144
........
r9186 | jonas | 2007-11-10 22:37:24 +0100 (Sat, 10 Nov 2007) | 2 lines

* regenerated for x86_64-darwin
........
r9215 | peter | 2007-11-12 18:07:23 +0100 (Mon, 12 Nov 2007) | 2 lines

* basic dependency handling is working
........
r9217 | peter | 2007-11-12 19:07:07 +0100 (Mon, 12 Nov 2007) | 2 lines

* default repository is now http
........
r9233 | peter | 2007-11-13 19:37:42 +0100 (Tue, 13 Nov 2007) | 2 lines

* pass --nofpccfg
........
r9240 | peter | 2007-11-13 20:35:17 +0100 (Tue, 13 Nov 2007) | 4 lines

* give better error on corrupt packages.xml
* first installdependencies before downloading/unzipping packages
* delete corrupt file if download failed
........
r9247 | peter | 2007-11-14 00:09:04 +0100 (Wed, 14 Nov 2007) | 3 lines

* support <none> as empty version
* don't write not installed versions to status file
........
r9255 | peter | 2007-11-15 00:08:56 +0100 (Thu, 15 Nov 2007) | 2 lines

* remove obsolete 2.0.x files
........
r9256 | peter | 2007-11-15 00:10:09 +0100 (Thu, 15 Nov 2007) | 4 lines

* split options in globaloptions and compileroptions
* use compileroptions to load settings for compiling fpmake
* simple version check in config files
........
r9257 | peter | 2007-11-15 00:13:22 +0100 (Thu, 15 Nov 2007) | 2 lines

* remove pkgcurl
........
r9258 | peter | 2007-11-15 00:15:46 +0100 (Thu, 15 Nov 2007) | 2 lines

* move example/test code to examples sub dir
........
r9259 | peter | 2007-11-15 00:16:55 +0100 (Thu, 15 Nov 2007) | 2 lines

* another example
........
r9282 | peter | 2007-11-18 18:25:25 +0100 (Sun, 18 Nov 2007) | 2 lines

* made pkglnet,pkgwget implicitunits
........
r9284 | peter | 2007-11-18 18:36:55 +0100 (Sun, 18 Nov 2007) | 2 lines

* Add path to URI request
........
r9285 | peter | 2007-11-18 18:48:35 +0100 (Sun, 18 Nov 2007) | 2 lines

* fixed case downloadpackage action
........
r9305 | peter | 2007-11-20 23:01:22 +0100 (Tue, 20 Nov 2007) | 3 lines

* check if the minimum required fpmkunit is installed, if not
installed or too old then fallback to internal source
........
r9306 | peter | 2007-11-20 23:23:41 +0100 (Tue, 20 Nov 2007) | 2 lines

* check for all fpmkunit dependencies with version check
........
r9314 | peter | 2007-11-21 23:00:48 +0100 (Wed, 21 Nov 2007) | 2 lines

* Use expandfilename to remove ../.. from FPCDIR for non-unix
........
r9355 | peter | 2007-11-30 01:15:50 +0100 (Fri, 30 Nov 2007) | 2 lines

* stop when fpmake fails
........
r9654 | peter | 2008-01-06 18:15:12 +0100 (Sun, 06 Jan 2008) | 2 lines

* updated
........
r9688 | peter | 2008-01-09 00:44:55 +0100 (Wed, 09 Jan 2008) | 2 lines

* regenerated
........

git-svn-id: branches/fixes_2_2@9760 -

peter 17 éve
szülő
commit
d1b4bdae25
49 módosított fájl, 6651 hozzáadás és 5939 törlés
  1. 9 13
      .gitattributes
  2. 0 0
      utils/fppkg/examples/pkglibcurl.pp
  3. 0 0
      utils/fppkg/examples/pkgocurl.pp
  4. 0 0
      utils/fppkg/examples/pkgsynapse.pp
  5. 0 0
      utils/fppkg/examples/rep2xml.lpi
  6. 0 0
      utils/fppkg/examples/rep2xml.lpr
  7. 0 0
      utils/fppkg/examples/testdownload.pp
  8. 0 0
      utils/fppkg/examples/testrep.pp
  9. 0 2344
      utils/fppkg/fcl20/contnrs.pp
  10. 0 363
      utils/fppkg/fcl20/streamcoll.pp
  11. 0 425
      utils/fppkg/fcl20/uriparser.pp
  12. 0 1470
      utils/fppkg/fcl20/zipper.pp
  13. 0 440
      utils/fppkg/fcl20/zstream.pp
  14. 58 0
      utils/fppkg/fpmake.pp
  15. 5062 0
      utils/fppkg/fpmkunitsrc.inc
  16. 102 102
      utils/fppkg/fppkg.lpi
  17. 71 54
      utils/fppkg/fppkg.pp
  18. 101 101
      utils/fppkg/fprepos.pp
  19. 5 1
      utils/fppkg/lnet/lcommon.pp
  20. 1 1
      utils/fppkg/lnet/lcontrolstack.pp
  21. 10 1
      utils/fppkg/lnet/levents.pp
  22. 1 1
      utils/fppkg/lnet/lfastcgi.pp
  23. 6 6
      utils/fppkg/lnet/lftp.pp
  24. 1 1
      utils/fppkg/lnet/lhttp.pp
  25. 1 4
      utils/fppkg/lnet/lhttputil.pp
  26. 23 0
      utils/fppkg/lnet/lmimestreams.pp
  27. 1 1
      utils/fppkg/lnet/lmimetypes.pp
  28. 37 6
      utils/fppkg/lnet/lmimewrapper.pp
  29. 64 16
      utils/fppkg/lnet/lnet.pp
  30. 1 1
      utils/fppkg/lnet/lprocess.pp
  31. 91 143
      utils/fppkg/lnet/lsmtp.pp
  32. 23 0
      utils/fppkg/lnet/lspawnfcgi.pp
  33. 1 1
      utils/fppkg/lnet/lstrbuffer.pp
  34. 6 6
      utils/fppkg/lnet/ltelnet.pp
  35. 23 0
      utils/fppkg/lnet/ltimer.pp
  36. 1 1
      utils/fppkg/lnet/lwebserver.pp
  37. 3 0
      utils/fppkg/lnet/sys/lepolleventer.inc
  38. 4 0
      utils/fppkg/lnet/sys/lkqueueeventer.inc
  39. 0 137
      utils/fppkg/pkgarchive.pp
  40. 175 17
      utils/fppkg/pkgcommands.pp
  41. 47 22
      utils/fppkg/pkgdownload.pp
  42. 166 28
      utils/fppkg/pkgfpmake.pp
  43. 95 11
      utils/fppkg/pkgglobals.pp
  44. 29 9
      utils/fppkg/pkghandler.pp
  45. 2 3
      utils/fppkg/pkglnet.pp
  46. 22 6
      utils/fppkg/pkgmessages.pp
  47. 288 173
      utils/fppkg/pkgoptions.pp
  48. 120 30
      utils/fppkg/pkgrepos.pp
  49. 1 1
      utils/fppkg/pkgwget.pp

+ 9 - 13
.gitattributes

@@ -8842,11 +8842,15 @@ utils/fpmc/test.mc -text
 utils/fppkg/Makefile svneol=native#text/plain
 utils/fppkg/Makefile.fpc svneol=native#text/plain
 utils/fppkg/README svneol=native#text/plain
-utils/fppkg/fcl20/contnrs.pp svneol=native#text/plain
-utils/fppkg/fcl20/streamcoll.pp svneol=native#text/plain
-utils/fppkg/fcl20/uriparser.pp svneol=native#text/plain
-utils/fppkg/fcl20/zipper.pp svneol=native#text/plain
-utils/fppkg/fcl20/zstream.pp svneol=native#text/plain
+utils/fppkg/examples/pkglibcurl.pp svneol=native#text/plain
+utils/fppkg/examples/pkgocurl.pp svneol=native#text/plain
+utils/fppkg/examples/pkgsynapse.pp svneol=native#text/plain
+utils/fppkg/examples/rep2xml.lpi svneol=native#text/plain
+utils/fppkg/examples/rep2xml.lpr svneol=native#text/plain
+utils/fppkg/examples/testdownload.pp svneol=native#text/plain
+utils/fppkg/examples/testrep.pp svneol=native#text/plain
+utils/fppkg/fpmake.pp svneol=native#text/plain
+utils/fppkg/fpmkunitsrc.inc svneol=native#text/plain
 utils/fppkg/fppkg.lpi svneol=native#text/plain
 utils/fppkg/fppkg.pp svneol=native#text/plain
 utils/fppkg/fprepos.pp svneol=native#text/plain
@@ -8881,25 +8885,17 @@ utils/fppkg/lnet/sys/lkqueueeventerh.inc svneol=native#text/plain
 utils/fppkg/lnet/sys/lspawnfcgiunix.inc svneol=native#text/plain
 utils/fppkg/lnet/sys/lspawnfcgiwin.inc svneol=native#text/plain
 utils/fppkg/lnet/sys/osunits.inc svneol=native#text/plain
-utils/fppkg/pkgarchive.pp svneol=native#text/plain
 utils/fppkg/pkgcommands.pp svneol=native#text/plain
 utils/fppkg/pkgdownload.pp svneol=native#text/plain
 utils/fppkg/pkgfpmake.pp svneol=native#text/plain
 utils/fppkg/pkgglobals.pp svneol=native#text/plain
 utils/fppkg/pkghandler.pp svneol=native#text/plain
-utils/fppkg/pkglibcurl.pp svneol=native#text/plain
 utils/fppkg/pkglnet.pp svneol=native#text/plain
 utils/fppkg/pkgmessages.pp svneol=native#text/plain
 utils/fppkg/pkgmkconv.pp svneol=native#text/plain
-utils/fppkg/pkgocurl.pp svneol=native#text/plain
 utils/fppkg/pkgoptions.pp svneol=native#text/plain
 utils/fppkg/pkgrepos.pp svneol=native#text/plain
-utils/fppkg/pkgsynapse.pp svneol=native#text/plain
 utils/fppkg/pkgwget.pp svneol=native#text/plain
-utils/fppkg/rep2xml.lpi svneol=native#text/plain
-utils/fppkg/rep2xml.lpr svneol=native#text/plain
-utils/fppkg/reptest.pp svneol=native#text/plain
-utils/fppkg/testdownload.pp svneol=native#text/plain
 utils/fprcp/Makefile svneol=native#text/plain
 utils/fprcp/Makefile.fpc svneol=native#text/plain
 utils/fprcp/Readme.txt svneol=native#text/plain

+ 0 - 0
utils/fppkg/pkglibcurl.pp → utils/fppkg/examples/pkglibcurl.pp


+ 0 - 0
utils/fppkg/pkgocurl.pp → utils/fppkg/examples/pkgocurl.pp


+ 0 - 0
utils/fppkg/pkgsynapse.pp → utils/fppkg/examples/pkgsynapse.pp


+ 0 - 0
utils/fppkg/rep2xml.lpi → utils/fppkg/examples/rep2xml.lpi


+ 0 - 0
utils/fppkg/rep2xml.lpr → utils/fppkg/examples/rep2xml.lpr


+ 0 - 0
utils/fppkg/testdownload.pp → utils/fppkg/examples/testdownload.pp


+ 0 - 0
utils/fppkg/reptest.pp → utils/fppkg/examples/testrep.pp


+ 0 - 2344
utils/fppkg/fcl20/contnrs.pp

@@ -1,2344 +0,0 @@
-{
-    This file is part of the Free Component Library (FCL)
-    Copyright (c) 2002 by Florian Klaempfl
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-{$ifdef fpc}
-{$mode objfpc}
-{$endif}
-{$H+}
-{$ifdef CLASSESINLINE}{$inline on}{$endif}
-
-unit contnrs;
-
-interface
-
-uses
-  SysUtils,Classes;
-
-
-Type
-  TObjectListCallback = procedure(data:TObject;arg:pointer) of object;
-  TObjectListStaticCallback = procedure(data:TObject;arg:pointer);
-
-  TFPObjectList = class(TObject)
-  private
-    FFreeObjects : Boolean;
-    FList: TFPList;
-    function GetCount: integer;
-    procedure SetCount(const AValue: integer);
-  protected
-    function GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
-    procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
-    procedure SetCapacity(NewCapacity: Integer);
-    function GetCapacity: integer;
-  public
-    constructor Create;
-    constructor Create(FreeObjects : Boolean);
-    destructor Destroy; override;
-    procedure Clear;
-    function Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
-    procedure Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
-    procedure Exchange(Index1, Index2: Integer);
-    function Expand: TFPObjectList;
-    function Extract(Item: TObject): TObject;
-    function Remove(AObject: TObject): Integer;
-    function IndexOf(AObject: TObject): Integer;
-    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
-    procedure Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
-    function First: TObject;
-    function Last: TObject;
-    procedure Move(CurIndex, NewIndex: Integer);
-    procedure Assign(Obj:TFPObjectList);
-    procedure Pack;
-    procedure Sort(Compare: TListSortCompare);
-    procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
-    procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
-    property Capacity: Integer read GetCapacity write SetCapacity;
-    property Count: Integer read GetCount write SetCount;
-    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
-    property Items[Index: Integer]: TObject read GetItem write SetItem; default;
-    property List: TFPList read FList;
-  end;
-
-
-  TObjectList = class(TList)
-  private
-    ffreeobjects : boolean;
-  Protected
-    Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
-    function GetItem(Index: Integer): TObject;
-    Procedure SetItem(Index: Integer; AObject: TObject);
-  public
-    constructor create;
-    constructor create(freeobjects : boolean);
-    function Add(AObject: TObject): Integer;
-    function Extract(Item: TObject): TObject;
-    function Remove(AObject: TObject): Integer;
-    function IndexOf(AObject: TObject): Integer;
-    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
-    Procedure Insert(Index: Integer; AObject: TObject);
-    function First: TObject;
-    Function Last: TObject;
-    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
-    property Items[Index: Integer]: TObject read GetItem write SetItem; default;
-  end;
-
-  TComponentList = class(TObjectList)
-  Private
-    FNotifier : TComponent;
-  Protected
-    Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
-    Function GetItems(Index: Integer): TComponent;
-    Procedure SetItems(Index: Integer; AComponent: TComponent);
-    Procedure HandleFreeNotify(Sender: TObject; AComponent: TComponent);
-  public
-    destructor Destroy; override;
-    Function Add(AComponent: TComponent): Integer;
-    Function Extract(Item: TComponent): TComponent;
-    Function Remove(AComponent: TComponent): Integer;
-    Function IndexOf(AComponent: TComponent): Integer;
-    Function First: TComponent;
-    Function Last: TComponent;
-    Procedure Insert(Index: Integer; AComponent: TComponent);
-    property Items[Index: Integer]: TComponent read GetItems write SetItems; default;
-  end;
-
-  TClassList = class(TList)
-  protected
-    Function GetItems(Index: Integer): TClass;
-    Procedure SetItems(Index: Integer; AClass: TClass);
-  public
-    Function Add(AClass: TClass): Integer;
-    Function Extract(Item: TClass): TClass;
-    Function Remove(AClass: TClass): Integer;
-    Function IndexOf(AClass: TClass): Integer;
-    Function First: TClass;
-    Function Last: TClass;
-    Procedure Insert(Index: Integer; AClass: TClass);
-    property Items[Index: Integer]: TClass read GetItems write SetItems; default;
-  end;
-
-  TOrderedList = class(TObject)
-  private
-    FList: TList;
-  protected
-    Procedure PushItem(AItem: Pointer); virtual; abstract;
-    Function PopItem: Pointer; virtual;
-    Function PeekItem: Pointer; virtual;
-    property List: TList read FList;
-  public
-    constructor Create;
-    destructor Destroy; override;
-    Function Count: Integer;
-    Function AtLeast(ACount: Integer): Boolean;
-    Function Push(AItem: Pointer): Pointer;
-    Function Pop: Pointer;
-    Function Peek: Pointer;
-  end;
-
-{ TStack class }
-
-  TStack = class(TOrderedList)
-  protected
-    Procedure PushItem(AItem: Pointer); override;
-  end;
-
-{ TObjectStack class }
-
-  TObjectStack = class(TStack)
-  public
-    Function Push(AObject: TObject): TObject;
-    Function Pop: TObject;
-    Function Peek: TObject;
-  end;
-
-{ TQueue class }
-
-  TQueue = class(TOrderedList)
-  protected
-    Procedure PushItem(AItem: Pointer); override;
-  end;
-
-{ TObjectQueue class }
-
-  TObjectQueue = class(TQueue)
-  public
-    Function Push(AObject: TObject): TObject;
-    Function Pop: TObject;
-    Function Peek: TObject;
-  end;
-
-{ ---------------------------------------------------------------------
-    TFPList with Hash support
-  ---------------------------------------------------------------------}
-
-type
-  THashItem=record
-    HashValue : LongWord;
-    StrIndex  : Integer;
-    NextIndex : Integer;
-    Data      : Pointer;
-  end;
-  PHashItem=^THashItem;
-
-const
-  MaxHashListSize = Maxint div 16;
-  MaxHashStrSize  = Maxint;
-  MaxHashTableSize = Maxint div 4;
-  MaxItemsPerHash = 3;
-
-type
-  PHashItemList = ^THashItemList;
-  THashItemList = array[0..MaxHashListSize - 1] of THashItem;
-  PHashTable = ^THashTable;
-  THashTable = array[0..MaxHashTableSize - 1] of Integer;
-
-  TFPHashList = class(TObject)
-  private
-    { ItemList }
-    FHashList     : PHashItemList;
-    FCount,
-    FCapacity : Integer;
-    { Hash }
-    FHashTable    : PHashTable;
-    FHashCapacity : Integer;
-    { Strings }
-    FStrs     : PChar;
-    FStrCount,
-    FStrCapacity : Integer;
-    function InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
-  protected
-    function Get(Index: Integer): Pointer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure Put(Index: Integer; Item: Pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure SetCapacity(NewCapacity: Integer);
-    procedure SetCount(NewCount: Integer);
-    Procedure RaiseIndexError(Index : Integer);
-    function  AddStr(const s:shortstring): Integer;
-    procedure AddToHashTable(Index: Integer);
-    procedure StrExpand(MinIncSize:Integer);
-    procedure SetStrCapacity(NewCapacity: Integer);
-    procedure SetHashCapacity(NewCapacity: Integer);
-    procedure ReHash;
-  public
-    constructor Create;
-    destructor Destroy; override;
-    function Add(const AName:shortstring;Item: Pointer): Integer;
-    procedure Clear;
-    function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure Delete(Index: Integer);
-    class procedure Error(const Msg: string; Data: PtrInt);
-    function Expand: TFPHashList;
-    function Extract(item: Pointer): Pointer;
-    function IndexOf(Item: Pointer): Integer;
-    function Find(const AName:shortstring): Pointer;
-    function FindIndexOf(const AName:shortstring): Integer;
-    function FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
-    function Rename(const AOldName,ANewName:shortstring): Integer;
-    function Remove(Item: Pointer): Integer;
-    procedure Pack;
-    procedure ShowStatistics;
-    procedure ForEachCall(proc2call:TListCallback;arg:pointer);
-    procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
-    property Capacity: Integer read FCapacity write SetCapacity;
-    property Count: Integer read FCount write SetCount;
-    property Items[Index: Integer]: Pointer read Get write Put; default;
-    property List: PHashItemList read FHashList;
-    property Strs: PChar read FStrs;
-  end;
-
-
-{*******************************************************
-        TFPHashObjectList (From fcl/inc/contnrs.pp)
-********************************************************}
-
-  TFPHashObjectList = class;
-
-  { TFPHashObject }
-
-  TFPHashObject = class
-  private
-    FOwner     : TFPHashObjectList;
-    FCachedStr : pshortstring;
-    FStrIndex  : Integer;
-    procedure InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:shortstring);
-  protected
-    function GetName:shortstring;virtual;
-    function GetHash:Longword;virtual;
-  public
-    constructor CreateNotOwned;
-    constructor Create(HashObjectList:TFPHashObjectList;const s:shortstring);
-    procedure ChangeOwner(HashObjectList:TFPHashObjectList); {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:shortstring); {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure Rename(const ANewName:shortstring);
-    property Name:shortstring read GetName;
-    property Hash:Longword read GetHash;
-  end;
-
-  TFPHashObjectList = class(TObject)
-  private
-    FFreeObjects : Boolean;
-    FHashList: TFPHashList;
-    function GetCount: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure SetCount(const AValue: integer); {$ifdef CCLASSESINLINE}inline;{$endif}
-  protected
-    function GetItem(Index: Integer): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure SetCapacity(NewCapacity: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
-    function GetCapacity: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-  public
-    constructor Create(FreeObjects : boolean = True);
-    destructor Destroy; override;
-    procedure Clear;
-    function Add(const AName:shortstring;AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure Delete(Index: Integer);
-    function Expand: TFPHashObjectList; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function Remove(AObject: TObject): Integer;
-    function IndexOf(AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function Find(const s:shortstring): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function FindIndexOf(const s:shortstring): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
-    function Rename(const AOldName,ANewName:shortstring): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
-    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
-    procedure Pack; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure ShowStatistics; {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
-    procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
-    property Capacity: Integer read GetCapacity write SetCapacity;
-    property Count: Integer read GetCount write SetCount;
-    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
-    property Items[Index: Integer]: TObject read GetItem write SetItem; default;
-    property List: TFPHashList read FHashList;
-  end;
-
-{ ---------------------------------------------------------------------
-    Hash support, implemented by Dean Zobec
-  ---------------------------------------------------------------------}
-
-
-  { Must return a Longword value in the range 0..TableSize,
-   usually via a mod operator;  }
-  THashFunction = function(const S: string; const TableSize: Longword): Longword;
-
-
-  { THTNode }
-
-  THTCustomNode = class(TObject)
-  private
-    FKey: string;
-  public
-    constructor CreateWith(const AString: String);
-    function HasKey(const AKey: string): boolean;
-    property Key: string read FKey;
-  end;
-  THTCustomNodeClass = Class of THTCustomNode;
-
-
-  { TFPCustomHashTable }
-
-  TFPCustomHashTable = class(TObject)
-  private
-    FHashTable: TFPObjectList;
-    FHashTableSize: Longword;
-    FHashFunction: THashFunction;
-    FCount: Longword;
-    function GetDensity: Longword;
-    function GetNumberOfCollisions: Longword;
-    procedure SetHashTableSize(const Value: Longword);
-    procedure InitializeHashTable;
-    function GetVoidSlots: Longword;
-    function GetLoadFactor: double;
-    function GetAVGChainLen: double;
-    function GetMaxChainLength: Longword;
-    function Chain(const index: Longword):TFPObjectList;
-  protected
-    Function CreateNewNode(const aKey : string) : THTCustomNode; virtual; abstract;
-    Procedure AddNode(ANode : THTCustomNode); virtual; abstract;
-    function ChainLength(const ChainIndex: Longword): Longword; virtual;
-    function FindOrCreateNew(const aKey: string): THTCustomNode; virtual;
-    procedure SetHashFunction(AHashFunction: THashFunction); virtual;
-    Function FindChainForAdd(Const aKey : String) : TFPObjectList;
-  public
-    constructor Create;
-    constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction);
-    destructor Destroy; override;
-    procedure ChangeTableSize(const ANewSize: Longword); virtual;
-    procedure Clear; virtual;
-    procedure Delete(const aKey: string); virtual;
-    function Find(const aKey: string): THTCustomNode;
-    function IsEmpty: boolean;
-    property HashFunction: THashFunction read FHashFunction write SetHashFunction;
-    property Count: Longword read FCount;
-    property HashTableSize: Longword read FHashTableSize write SetHashTableSize;
-    property HashTable: TFPObjectList read FHashTable;
-    property VoidSlots: Longword read GetVoidSlots;
-    property LoadFactor: double read GetLoadFactor;
-    property AVGChainLen: double read GetAVGChainLen;
-    property MaxChainLength: Longword read GetMaxChainLength;
-    property NumberOfCollisions: Longword read GetNumberOfCollisions;
-    property Density: Longword read GetDensity;
-  end;
-
-  { TFPDataHashTable : Hash table with simple data pointers }
-
-  THTDataNode = Class(THTCustomNode)
-  Private
-    FData: pointer;
-  public
-    property Data: pointer read FData write FData;
-  end;
-  // For compatibility
-  THTNode = THTDataNode;
-
-  TDataIteratorMethod = procedure(Item: Pointer; const Key: string; var Continue: Boolean) of object;
-  // For compatibility
-  TIteratorMethod = TDataIteratorMethod;
-
-  TFPDataHashTable = Class(TFPCustomHashTable)
-  Protected
-    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
-    Procedure AddNode(ANode : THTCustomNode); override;
-    procedure SetData(const index: string; const AValue: Pointer); virtual;
-    function GetData(const index: string):Pointer; virtual;
-    function ForEachCall(aMethod: TDataIteratorMethod): THTDataNode; virtual;
-  Public
-    procedure Add(const aKey: string; AItem: pointer); virtual;
-    property Items[const index: string]: Pointer read GetData write SetData; default;
-  end;
-
-  { TFPStringHashTable : Hash table with simple strings as data }
-  THTStringNode = Class(THTCustomNode)
-  Private
-    FData : String;
-  public
-    property Data: String read FData write FData;
-  end;
-  TStringIteratorMethod = procedure(Item: String; const Key: string; var Continue: Boolean) of object;
-
-  TFPStringHashTable = Class(TFPCustomHashTable)
-  Protected
-    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
-    Procedure AddNode(ANode : THTCustomNode); override;
-    procedure SetData(const Index, AValue: string); virtual;
-    function GetData(const index: string): String; virtual;
-    function ForEachCall(aMethod: TStringIteratorMethod): THTStringNode; virtual;
-  Public
-    procedure Add(const aKey,aItem: string); virtual;
-    property Items[const index: string]: String read GetData write SetData; default;
-  end;
-
-  { TFPStringHashTable : Hash table with simple strings as data }
-
-
-  THTObjectNode = Class(THTCustomNode)
-  Private
-    FData : TObject;
-  public
-    property Data: TObject read FData write FData;
-  end;
-
-  THTOwnedObjectNode = Class(THTObjectNode)
-  public
-    Destructor Destroy; override;
-  end;
-  TObjectIteratorMethod = procedure(Item: TObject; const Key: string; var Continue: Boolean) of object;
-
-  TFPObjectHashTable = Class(TFPCustomHashTable)
-  Private
-    FOwnsObjects : Boolean;
-  Protected
-    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
-    Procedure AddNode(ANode : THTCustomNode); override;
-    procedure SetData(const Index: string; AObject : TObject); virtual;
-    function GetData(const index: string): TObject; virtual;
-    function ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode; virtual;
-  Public
-    constructor Create(AOwnsObjects : Boolean = True);
-    constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True);
-    procedure Add(const aKey: string; AItem : TObject); virtual;
-    property Items[const index: string]: TObject read GetData write SetData; default;
-    Property OwnsObjects : Boolean Read FOwnsObjects Write FOwnsObjects;
-  end;
-
-
-  EDuplicate = class(Exception);
-  EKeyNotFound = class(Exception);
-
-
-  function RSHash(const S: string; const TableSize: Longword): Longword;
-
-implementation
-
-uses
-  RtlConsts;
-
-ResourceString
-  DuplicateMsg = 'An item with key %0:s already exists';
-  KeyNotFoundMsg = 'Method: %0:s key [''%1:s''] not found in container';
-  NotEmptyMsg = 'Hash table not empty.';
-
-const
-  NPRIMES = 28;
-
-  PRIMELIST: array[0 .. NPRIMES-1] of Longword =
-  ( 53,         97,         193,       389,       769,
-    1543,       3079,       6151,      12289,     24593,
-    49157,      98317,      196613,    393241,    786433,
-    1572869,    3145739,    6291469,   12582917,  25165843,
-    50331653,   100663319,  201326611, 402653189, 805306457,
-    1610612741, 3221225473, 4294967291 );
-
-constructor TFPObjectList.Create(FreeObjects : boolean);
-begin
-  Create;
-  FFreeObjects := Freeobjects;
-end;
-
-destructor TFPObjectList.Destroy;
-begin
-  if (FList <> nil) then
-  begin
-    Clear;
-    FList.Destroy;
-  end;
-  inherited Destroy;
-end;
-
-procedure TFPObjectList.Clear;
-var
-  i: integer;
-begin
-  if FFreeObjects then
-    for i := 0 to FList.Count - 1 do
-      TObject(FList[i]).Free;
-  FList.Clear;
-end;
-
-constructor TFPObjectList.Create;
-begin
-  inherited Create;
-  FList := TFPList.Create;
-  FFreeObjects := True;
-end;
-
-function TFPObjectList.GetCount: integer;
-begin
-  Result := FList.Count;
-end;
-
-procedure TFPObjectList.SetCount(const AValue: integer);
-begin
-  if FList.Count <> AValue then
-    FList.Count := AValue;
-end;
-
-function TFPObjectList.GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
-begin
-  Result := TObject(FList[Index]);
-end;
-
-procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
-begin
-  if OwnsObjects then
-    TObject(FList[Index]).Free;
-  FList[index] := AObject;
-end;
-
-procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
-begin
-  FList.Capacity := NewCapacity;
-end;
-
-function TFPObjectList.GetCapacity: integer;
-begin
-  Result := FList.Capacity;
-end;
-
-function TFPObjectList.Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
-begin
-  Result := FList.Add(AObject);
-end;
-
-procedure TFPObjectList.Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
-begin
-  if OwnsObjects then
-    TObject(FList[Index]).Free;
-  FList.Delete(Index);
-end;
-
-procedure TFPObjectList.Exchange(Index1, Index2: Integer);
-begin
-  FList.Exchange(Index1, Index2);
-end;
-
-function TFPObjectList.Expand: TFPObjectList;
-begin
-  FList.Expand;
-  Result := Self;
-end;
-
-function TFPObjectList.Extract(Item: TObject): TObject;
-begin
-  Result := TObject(FList.Extract(Item));
-end;
-
-function TFPObjectList.Remove(AObject: TObject): Integer;
-begin
-  Result := IndexOf(AObject);
-  if (Result <> -1) then
-  begin
-    if OwnsObjects then
-      TObject(FList[Result]).Free;
-    FList.Delete(Result);
-  end;
-end;
-
-function TFPObjectList.IndexOf(AObject: TObject): Integer;
-begin
-  Result := FList.IndexOf(Pointer(AObject));
-end;
-
-function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
-var
-  I : Integer;
-begin
-  I:=AStartAt;
-  Result:=-1;
-  If AExact then
-    while (I<Count) and (Result=-1) do
-      If Items[i].ClassType=AClass then
-        Result:=I
-      else
-        Inc(I)
-  else
-    while (I<Count) and (Result=-1) do
-      If Items[i].InheritsFrom(AClass) then
-        Result:=I
-      else
-        Inc(I);
-end;
-
-procedure TFPObjectList.Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
-begin
-  FList.Insert(Index, Pointer(AObject));
-end;
-
-procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
-begin
-  FList.Move(CurIndex, NewIndex);
-end;
-
-procedure TFPObjectList.Assign(Obj: TFPObjectList);
-var
-  i: Integer;
-begin
-  Clear;
-  for I := 0 to Obj.Count - 1 do
-    Add(Obj[i]);
-end;
-
-procedure TFPObjectList.Pack;
-begin
-  FList.Pack;
-end;
-
-procedure TFPObjectList.Sort(Compare: TListSortCompare);
-begin
-  FList.Sort(Compare);
-end;
-
-function TFPObjectList.First: TObject;
-begin
-  Result := TObject(FList.First);
-end;
-
-function TFPObjectList.Last: TObject;
-begin
-  Result := TObject(FList.Last);
-end;
-
-procedure TFPObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
-begin
-  FList.ForEachCall(TListCallBack(proc2call),arg);
-end;
-
-procedure TFPObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
-begin
-  FList.ForEachCall(TListStaticCallBack(proc2call),arg);
-end;
-
-
-{ TObjectList }
-
-constructor tobjectlist.create(freeobjects : boolean);
-
-begin
-  inherited create;
-  ffreeobjects:=freeobjects;
-end;
-
-Constructor tobjectlist.create;
-
-begin
-  inherited create;
-  ffreeobjects:=True;
-end;
-
-Procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
-
-begin
-  if FFreeObjects then
-    if (Action=lnDeleted) then
-      TObject(Ptr).Free;
-  inherited Notify(Ptr,Action);
-end;
-
-
-Function TObjectList.GetItem(Index: Integer): TObject;
-
-begin
-  Result:=TObject(Inherited Get(Index));
-end;
-
-
-Procedure TObjectList.SetItem(Index: Integer; AObject: TObject);
-
-Var
-  O : TObject;
-
-begin
-  if OwnsObjects then
-    begin
-    O:=GetItem(Index);
-    O.Free;
-    end;
-  Put(Index,Pointer(AObject));
-end;
-
-
-Function TObjectList.Add(AObject: TObject): Integer;
-
-begin
-  Result:=Inherited Add(Pointer(AObject));
-end;
-
-
-Function TObjectList.Extract(Item: TObject): TObject;
-
-begin
-  Result:=Tobject(Inherited Extract(Pointer(Item)));
-end;
-
-
-Function TObjectList.Remove(AObject: TObject): Integer;
-
-begin
-  Result:=Inherited Remove(Pointer(AObject));
-end;
-
-
-Function TObjectList.IndexOf(AObject: TObject): Integer;
-
-begin
-  Result:=Inherited indexOF(Pointer(AObject));
-end;
-
-
-Function TObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
-
-Var
-  I : Integer;
-
-begin
-  I:=AStartAt;
-  Result:=-1;
-  If AExact then
-    While (I<Count) and (Result=-1) do
-      If Items[i].ClassType=AClass then
-        Result:=I
-      else
-        Inc(I)
-  else
-    While (I<Count) and (Result=-1) do
-      If Items[i].InheritsFrom(AClass) then
-        Result:=I
-      else
-        Inc(I);
-end;
-
-
-procedure TObjectList.Insert(Index: Integer; AObject: TObject);
-begin
-  Inherited Insert(Index,Pointer(AObject));
-end;
-
-
-function TObjectList.First: TObject;
-
-begin
-  Result := TObject(Inherited First);
-end;
-
-
-function TObjectList.Last: TObject;
-
-begin
-  Result := TObject(Inherited Last);
-end;
-
-{ TListComponent }
-
-Type
-  TlistComponent = Class(TComponent)
-  Private
-    Flist : TComponentList;
-  Public
-    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
-  end;
-
-procedure TlistComponent.Notification(AComponent: TComponent;
-  Operation: TOperation);
-begin
-  If (Operation=opremove) then
-    Flist.HandleFreeNotify(Self,AComponent);
-  inherited;
-end;
-
-{ TComponentList }
-
-Function TComponentList.Add(AComponent: TComponent): Integer;
-begin
-  Result:=Inherited Add(AComponent);
-end;
-
-destructor TComponentList.Destroy;
-begin
-  inherited;
-  FreeAndNil(FNotifier);
-end;
-
-Function TComponentList.Extract(Item: TComponent): TComponent;
-begin
-  Result:=TComponent(Inherited Extract(Item));
-end;
-
-Function TComponentList.First: TComponent;
-begin
-  Result:=TComponent(Inherited First);
-end;
-
-Function TComponentList.GetItems(Index: Integer): TComponent;
-begin
-  Result:=TComponent(Inherited Items[Index]);
-end;
-
-Procedure TComponentList.HandleFreeNotify(Sender: TObject;
-  AComponent: TComponent);
-begin
-  Extract(Acomponent);
-end;
-
-Function TComponentList.IndexOf(AComponent: TComponent): Integer;
-begin
-  Result:=Inherited IndexOf(AComponent);
-end;
-
-Procedure TComponentList.Insert(Index: Integer; AComponent: TComponent);
-begin
-  Inherited Insert(Index,Acomponent)
-end;
-
-Function TComponentList.Last: TComponent;
-begin
-  Result:=TComponent(Inherited Last);
-end;
-
-Procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
-begin
-  If FNotifier=NIl then
-    begin
-    FNotifier:=TlistComponent.Create(nil);
-    TlistComponent(FNotifier).FList:=Self;
-    end;
-  If Assigned(Ptr) then
-    With TComponent(Ptr) do
-      case Action of
-        lnAdded : FreeNotification(FNotifier);
-        lnExtracted, lnDeleted: RemoveFreeNotification(FNotifier);
-      end;
-  inherited Notify(Ptr, Action);
-end;
-
-Function TComponentList.Remove(AComponent: TComponent): Integer;
-begin
-  Result:=Inherited Remove(AComponent);
-end;
-
-Procedure TComponentList.SetItems(Index: Integer; AComponent: TComponent);
-begin
-  Put(Index,AComponent);
-end;
-
-{ TClassList }
-
-Function TClassList.Add(AClass: TClass): Integer;
-begin
-  Result:=Inherited Add(Pointer(AClass));
-end;
-
-Function TClassList.Extract(Item: TClass): TClass;
-begin
-  Result:=TClass(Inherited Extract(Pointer(Item)));
-end;
-
-Function TClassList.First: TClass;
-begin
-  Result:=TClass(Inherited First);
-end;
-
-Function TClassList.GetItems(Index: Integer): TClass;
-begin
-  Result:=TClass(Inherited Items[Index]);
-end;
-
-Function TClassList.IndexOf(AClass: TClass): Integer;
-begin
-  Result:=Inherited IndexOf(Pointer(AClass));
-end;
-
-Procedure TClassList.Insert(Index: Integer; AClass: TClass);
-begin
-  Inherited Insert(index,Pointer(AClass));
-end;
-
-Function TClassList.Last: TClass;
-begin
-  Result:=TClass(Inherited Last);
-end;
-
-Function TClassList.Remove(AClass: TClass): Integer;
-begin
-  Result:=Inherited Remove(Pointer(AClass));
-end;
-
-Procedure TClassList.SetItems(Index: Integer; AClass: TClass);
-begin
-  Put(Index,Pointer(Aclass));
-end;
-
-{ TOrderedList }
-
-Function TOrderedList.AtLeast(ACount: Integer): Boolean;
-begin
-  Result:=(FList.Count>=Acount)
-end;
-
-Function TOrderedList.Count: Integer;
-begin
-  Result:=FList.Count;
-end;
-
-constructor TOrderedList.Create;
-begin
-  FList:=Tlist.Create;
-end;
-
-destructor TOrderedList.Destroy;
-begin
-  FList.Free;
-end;
-
-Function TOrderedList.Peek: Pointer;
-begin
-  If AtLeast(1) then
-    Result:=PeekItem
-  else
-    Result:=Nil;
-end;
-
-Function TOrderedList.PeekItem: Pointer;
-begin
-  With Flist do
-    Result:=Items[Count-1]
-end;
-
-Function TOrderedList.Pop: Pointer;
-begin
-  If Atleast(1) then
-    Result:=PopItem
-  else
-    Result:=Nil;
-end;
-
-Function TOrderedList.PopItem: Pointer;
-begin
-  With FList do
-    If Count>0 then
-      begin
-      Result:=Items[Count-1];
-      Delete(Count-1);
-      end
-    else
-      Result:=Nil;
-end;
-
-Function TOrderedList.Push(AItem: Pointer): Pointer;
-begin
-  PushItem(Aitem);
-  Result:=AItem;
-end;
-
-{ TStack }
-
-Procedure TStack.PushItem(AItem: Pointer);
-begin
-  FList.Add(Aitem);
-end;
-
-{ TObjectStack }
-
-Function TObjectStack.Peek: TObject;
-begin
-  Result:=TObject(Inherited Peek);
-end;
-
-Function TObjectStack.Pop: TObject;
-begin
-  Result:=TObject(Inherited Pop);
-end;
-
-Function TObjectStack.Push(AObject: TObject): TObject;
-begin
-  Result:=TObject(Inherited Push(Pointer(AObject)));
-end;
-
-{ TQueue }
-
-Procedure TQueue.PushItem(AItem: Pointer);
-begin
-  With Flist Do
-    Insert(0,AItem);
-end;
-
-{ TObjectQueue }
-
-Function TObjectQueue.Peek: TObject;
-begin
-  Result:=TObject(Inherited Peek);
-end;
-
-Function TObjectQueue.Pop: TObject;
-begin
-  Result:=TObject(Inherited Pop);
-end;
-
-Function TObjectQueue.Push(AObject: TObject): TObject;
-begin
-  Result:=TObject(Inherited Push(Pointer(Aobject)));
-end;
-
-
-{*****************************************************************************
-                            TFPHashList
-*****************************************************************************}
-
-    function FPHash1(const s:shortstring):LongWord;
-      Var
-        g : LongWord;
-        p,pmax : pchar;
-      begin
-        result:=0;
-        p:=@s[1];
-        pmax:=@s[length(s)+1];
-        while (p<pmax) do
-          begin
-            result:=result shl 4 + LongWord(p^);
-            g:=result and LongWord($F0000000);
-            if g<>0 then
-              result:=result xor (g shr 24) xor g;
-            inc(p);
-          end;
-        If result=0 then
-          result:=$ffffffff;
-      end;
-
-    function FPHash(const s:shortstring):LongWord;
-      Var
-        p,pmax : pchar;
-      begin
-{$ifopt Q+}
-{$define overflowon}
-{$Q-}
-{$endif}
-        result:=0;
-        p:=@s[1];
-        pmax:=@s[length(s)+1];
-        while (p<pmax) do
-          begin
-            result:=LongWord((result shl 5) - result) xor LongWord(P^);
-            inc(p);
-          end;
-{$ifdef overflowon}
-{$Q+}
-{$undef overflowon}
-{$endif}
-      end;
-
-
-procedure TFPHashList.RaiseIndexError(Index : Integer);
-begin
-  Error(SListIndexError, Index);
-end;
-
-
-function TFPHashList.Get(Index: Integer): Pointer;
-begin
-  If (Index < 0) or (Index >= FCount) then
-    RaiseIndexError(Index);
-  Result:=FHashList^[Index].Data;
-end;
-
-
-procedure TFPHashList.Put(Index: Integer; Item: Pointer);
-begin
-  if (Index < 0) or (Index >= FCount) then
-    RaiseIndexError(Index);
-  FHashList^[Index].Data:=Item;;
-end;
-
-
-function TFPHashList.NameOfIndex(Index: Integer): shortstring;
-begin
-  If (Index < 0) or (Index >= FCount) then
-    RaiseIndexError(Index);
-  with FHashList^[Index] do
-    begin
-      if StrIndex>=0 then
-        Result:=PShortString(@FStrs[StrIndex])^
-      else
-        Result:='';
-    end;
-end;
-
-
-function TFPHashList.HashOfIndex(Index: Integer): LongWord;
-begin
-  If (Index < 0) or (Index >= FCount) then
-    RaiseIndexError(Index);
-  Result:=FHashList^[Index].HashValue;
-end;
-
-
-function TFPHashList.Extract(item: Pointer): Pointer;
-var
-  i : Integer;
-begin
-  result := nil;
-  i := IndexOf(item);
-  if i >= 0 then
-   begin
-     Result := item;
-     Delete(i);
-   end;
-end;
-
-
-procedure TFPHashList.SetCapacity(NewCapacity: Integer);
-begin
-  If (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
-     Error (SListCapacityError, NewCapacity);
-  if NewCapacity = FCapacity then
-    exit;
-  ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
-  FCapacity := NewCapacity;
-end;
-
-
-procedure TFPHashList.SetCount(NewCount: Integer);
-begin
-  if (NewCount < 0) or (NewCount > MaxHashListSize)then
-    Error(SListCountError, NewCount);
-  If NewCount > FCount then
-    begin
-      If NewCount > FCapacity then
-        SetCapacity(NewCount);
-      If FCount < NewCount then
-        FillChar(FHashList^[FCount], (NewCount-FCount) div Sizeof(THashItem), 0);
-    end;
-  FCount := Newcount;
-end;
-
-
-procedure TFPHashList.SetStrCapacity(NewCapacity: Integer);
-begin
-  If (NewCapacity < FStrCount) or (NewCapacity > MaxHashStrSize) then
-     Error (SListCapacityError, NewCapacity);
-  if NewCapacity = FStrCapacity then
-    exit;
-  ReallocMem(FStrs, NewCapacity);
-  FStrCapacity := NewCapacity;
-end;
-
-
-procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
-begin
-  If (NewCapacity < 1) then
-    Error (SListCapacityError, NewCapacity);
-  if FHashCapacity=NewCapacity then
-    exit;
-  FHashCapacity:=NewCapacity;
-  ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
-  ReHash;
-end;
-
-
-procedure TFPHashList.ReHash;
-var
-  i : Integer;
-begin
-  FillDword(FHashTable^,FHashCapacity,LongWord(-1));
-  For i:=0 To FCount-1 Do
-    AddToHashTable(i);
-end;
-
-
-constructor TFPHashList.Create;
-begin
-  SetHashCapacity(1);
-end;
-
-
-destructor TFPHashList.Destroy;
-begin
-  Clear;
-  if assigned(FHashTable) then
-    FreeMem(FHashTable);
-  inherited Destroy;
-end;
-
-
-function TFPHashList.AddStr(const s:shortstring): Integer;
-var
-  Len : Integer;
-begin
-  len:=length(s)+1;
-  if FStrCount+Len >= FStrCapacity then
-    StrExpand(Len);
-  System.Move(s[0],FStrs[FStrCount],Len);
-  result:=FStrCount;
-  inc(FStrCount,Len);
-end;
-
-
-procedure TFPHashList.AddToHashTable(Index: Integer);
-var
-  HashIndex : Integer;
-begin
-  with FHashList^[Index] do
-    begin
-      if not assigned(Data) then
-        exit;
-      HashIndex:=HashValue mod LongWord(FHashCapacity);
-      NextIndex:=FHashTable^[HashIndex];
-      FHashTable^[HashIndex]:=Index;
-    end;
-end;
-
-
-function TFPHashList.Add(const AName:shortstring;Item: Pointer): Integer;
-begin
-  if FCount = FCapacity then
-    Expand;
-  with FHashList^[FCount] do
-    begin
-      HashValue:=FPHash(AName);
-      Data:=Item;
-      StrIndex:=AddStr(AName);
-    end;
-  AddToHashTable(FCount);
-  Result := FCount;
-  inc(FCount);
-end;
-
-procedure TFPHashList.Clear;
-begin
-  if Assigned(FHashList) then
-    begin
-      FCount:=0;
-      SetCapacity(0);
-      FHashList := nil;
-    end;
-  SetHashCapacity(1);
-  if Assigned(FStrs) then
-    begin
-      FStrCount:=0;
-      SetStrCapacity(0);
-      FStrs := nil;
-    end;
-end;
-
-procedure TFPHashList.Delete(Index: Integer);
-begin
-  If (Index<0) or (Index>=FCount) then
-    Error (SListIndexError, Index);
-  { Remove from HashList }
-  dec(FCount);
-  System.Move (FHashList^[Index+1], FHashList^[Index], (FCount - Index) * Sizeof(THashItem));
-  { All indexes are updated, we need to build the hashtable again }
-  Rehash;
-  { Shrink the list if appropriate }
-  if (FCapacity > 256) and (FCount < FCapacity shr 2) then
-    begin
-      FCapacity := FCapacity shr 1;
-      ReallocMem(FHashList, Sizeof(THashItem) * FCapacity);
-    end;
-end;
-
-function TFPHashList.Remove(Item: Pointer): Integer;
-begin
-  Result := IndexOf(Item);
-  If Result <> -1 then
-    Self.Delete(Result);
-end;
-
-class procedure TFPHashList.Error(const Msg: string; Data: PtrInt);
-begin
-  Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
-end;
-
-function TFPHashList.Expand: TFPHashList;
-var
-  IncSize : Longint;
-begin
-  Result := Self;
-  if FCount < FCapacity then
-    exit;
-  IncSize := sizeof(ptrint)*2;
-  if FCapacity > 127 then
-    Inc(IncSize, FCapacity shr 2)
-  else if FCapacity > sizeof(ptrint)*3 then
-    Inc(IncSize, FCapacity shr 1)
-  else if FCapacity >= sizeof(ptrint) then
-    inc(IncSize,sizeof(ptrint));
-  SetCapacity(FCapacity + IncSize);
-  { Maybe expand hash also }
-  if FCount>FHashCapacity*MaxItemsPerHash then
-    SetHashCapacity(FCount div MaxItemsPerHash);
-end;
-
-procedure TFPHashList.StrExpand(MinIncSize:Integer);
-var
-  IncSize : Longint;
-begin
-  if FStrCount+MinIncSize < FStrCapacity then
-    exit;
-  IncSize := 64;
-  if FStrCapacity > 255 then
-    Inc(IncSize, FStrCapacity shr 2);
-  SetStrCapacity(FStrCapacity + IncSize + MinIncSize);
-end;
-
-function TFPHashList.IndexOf(Item: Pointer): Integer;
-var
-  psrc  : PHashItem;
-  Index : integer;
-begin
-  Result:=-1;
-  psrc:=@FHashList^[0];
-  For Index:=0 To FCount-1 Do
-    begin
-      if psrc^.Data=Item then
-        begin
-          Result:=Index;
-          exit;
-        end;
-      inc(psrc);
-    end;
-end;
-
-function TFPHashList.InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
-var
-  HashIndex : Integer;
-  Len,
-  LastChar  : Char;
-begin
-  HashIndex:=AHash mod LongWord(FHashCapacity);
-  Result:=FHashTable^[HashIndex];
-  Len:=Char(Length(AName));
-  LastChar:=AName[Byte(Len)];
-  PrevIndex:=-1;
-  while Result<>-1 do
-    begin
-      with FHashList^[Result] do
-        begin
-          if assigned(Data) and
-             (HashValue=AHash) and
-             (Len=FStrs[StrIndex]) and
-             (LastChar=FStrs[StrIndex+Byte(Len)]) and
-             (AName=PShortString(@FStrs[StrIndex])^) then
-            exit;
-          PrevIndex:=Result;
-          Result:=NextIndex;
-        end;
-    end;
-end;
-
-
-function TFPHashList.Find(const AName:shortstring): Pointer;
-var
-  Index,
-  PrevIndex : Integer;
-begin
-  Result:=nil;
-  Index:=InternalFind(FPHash(AName),AName,PrevIndex);
-  if Index=-1 then
-    exit;
-  Result:=FHashList^[Index].Data;
-end;
-
-
-function TFPHashList.FindIndexOf(const AName:shortstring): Integer;
-var
-  PrevIndex : Integer;
-begin
-  Result:=InternalFind(FPHash(AName),AName,PrevIndex);
-end;
-
-
-function TFPHashList.FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
-var
-  Index,
-  PrevIndex : Integer;
-begin
-  Result:=nil;
-  Index:=InternalFind(AHash,AName,PrevIndex);
-  if Index=-1 then
-    exit;
-  Result:=FHashList^[Index].Data;
-end;
-
-
-function TFPHashList.Rename(const AOldName,ANewName:shortstring): Integer;
-var
-  PrevIndex,
-  Index : Integer;
-  OldHash : LongWord;
-begin
-  Result:=-1;
-  OldHash:=FPHash(AOldName);
-  Index:=InternalFind(OldHash,AOldName,PrevIndex);
-  if Index=-1 then
-    exit;
-  { Remove from current Hash }
-  if PrevIndex<>-1 then
-    FHashList^[PrevIndex].NextIndex:=FHashList^[Index].NextIndex
-  else
-    FHashTable^[OldHash mod LongWord(FHashCapacity)]:=FHashList^[Index].NextIndex;
-  { Set new name and hash }
-  with FHashList^[Index] do
-    begin
-      HashValue:=FPHash(ANewName);
-      StrIndex:=AddStr(ANewName);
-    end;
-  { Insert back in Hash }
-  AddToHashTable(Index);
-  { Return Index }
-  Result:=Index;
-end;
-
-procedure TFPHashList.Pack;
-var
-  NewCount,
-  i : integer;
-  pdest,
-  psrc : PHashItem;
-begin
-  NewCount:=0;
-  psrc:=@FHashList^[0];
-  pdest:=psrc;
-  For I:=0 To FCount-1 Do
-    begin
-      if assigned(psrc^.Data) then
-        begin
-          pdest^:=psrc^;
-          inc(pdest);
-          inc(NewCount);
-        end;
-      inc(psrc);
-    end;
-  FCount:=NewCount;
-  { We need to ReHash to update the IndexNext }
-  ReHash;
-  { Release over-capacity }
-  SetCapacity(FCount);
-  SetStrCapacity(FStrCount);
-end;
-
-
-procedure TFPHashList.ShowStatistics;
-var
-  HashMean,
-  HashStdDev : Double;
-  Index,
-  i,j : Integer;
-begin
-  { Calculate Mean and StdDev }
-  HashMean:=0;
-  HashStdDev:=0;
-  for i:=0 to FHashCapacity-1 do
-    begin
-      j:=0;
-      Index:=FHashTable^[i];
-      while (Index<>-1) do
-        begin
-          inc(j);
-          Index:=FHashList^[Index].NextIndex;
-        end;
-      HashMean:=HashMean+j;
-      HashStdDev:=HashStdDev+Sqr(j);
-    end;
-  HashMean:=HashMean/FHashCapacity;
-  HashStdDev:=(HashStdDev-FHashCapacity*Sqr(HashMean));
-  If FHashCapacity>1 then
-    HashStdDev:=Sqrt(HashStdDev/(FHashCapacity-1))
-  else
-    HashStdDev:=0;
-  { Print info to stdout }
-  Writeln('HashSize   : ',FHashCapacity);
-  Writeln('HashMean   : ',HashMean:1:4);
-  Writeln('HashStdDev : ',HashStdDev:1:4);
-  Writeln('ListSize   : ',FCount,'/',FCapacity);
-  Writeln('StringSize : ',FStrCount,'/',FStrCapacity);
-end;
-
-
-procedure TFPHashList.ForEachCall(proc2call:TListCallback;arg:pointer);
-var
-  i : integer;
-  p : pointer;
-begin
-  For I:=0 To Count-1 Do
-    begin
-      p:=FHashList^[i].Data;
-      if assigned(p) then
-        proc2call(p,arg);
-    end;
-end;
-
-
-procedure TFPHashList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
-var
-  i : integer;
-  p : pointer;
-begin
-  For I:=0 To Count-1 Do
-    begin
-      p:=FHashList^[i].Data;
-      if assigned(p) then
-        proc2call(p,arg);
-    end;
-end;
-
-
-{*****************************************************************************
-                               TFPHashObject
-*****************************************************************************}
-
-procedure TFPHashObject.InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:shortstring);
-var
-  Index : integer;
-begin
-  FOwner:=HashObjectList;
-  Index:=HashObjectList.Add(s,Self);
-  FStrIndex:=HashObjectList.List.List^[Index].StrIndex;
-  FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
-end;
-
-
-constructor TFPHashObject.CreateNotOwned;
-begin
-  FStrIndex:=-1;
-end;
-
-
-constructor TFPHashObject.Create(HashObjectList:TFPHashObjectList;const s:shortstring);
-begin
-  InternalChangeOwner(HashObjectList,s);
-end;
-
-
-procedure TFPHashObject.ChangeOwner(HashObjectList:TFPHashObjectList);
-begin
-  InternalChangeOwner(HashObjectList,PShortString(@FOwner.List.Strs[FStrIndex])^);
-end;
-
-
-procedure TFPHashObject.ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:shortstring);
-begin
-  InternalChangeOwner(HashObjectList,s);
-end;
-
-
-procedure TFPHashObject.Rename(const ANewName:shortstring);
-var
-  Index : integer;
-begin
-  Index:=FOwner.Rename(PShortString(@FOwner.List.Strs[FStrIndex])^,ANewName);
-  if Index<>-1 then
-    begin
-      FStrIndex:=FOwner.List.List^[Index].StrIndex;
-      FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
-    end;
-end;
-
-
-function TFPHashObject.GetName:shortstring;
-begin
-  if FOwner<>nil then
-    begin
-      FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
-      Result:=FCachedStr^;
-    end
-  else
-    Result:='';
-end;
-
-
-function TFPHashObject.GetHash:Longword;
-begin
-  if FOwner<>nil then
-    Result:=FPHash(PShortString(@FOwner.List.Strs[FStrIndex])^)
-  else
-    Result:=$ffffffff;
-end;
-
-
-{*****************************************************************************
-            TFPHashObjectList (Copied from rtl/objpas/classes/lists.inc)
-*****************************************************************************}
-
-constructor TFPHashObjectList.Create(FreeObjects : boolean = True);
-begin
-  inherited Create;
-  FHashList := TFPHashList.Create;
-  FFreeObjects := Freeobjects;
-end;
-
-destructor TFPHashObjectList.Destroy;
-begin
-  if (FHashList <> nil) then
-    begin
-      Clear;
-      FHashList.Destroy;
-    end;
-  inherited Destroy;
-end;
-
-procedure TFPHashObjectList.Clear;
-var
-  i: integer;
-begin
-  if FFreeObjects then
-    for i := 0 to FHashList.Count - 1 do
-      TObject(FHashList[i]).Free;
-  FHashList.Clear;
-end;
-
-function TFPHashObjectList.GetCount: integer;
-begin
-  Result := FHashList.Count;
-end;
-
-procedure TFPHashObjectList.SetCount(const AValue: integer);
-begin
-  if FHashList.Count <> AValue then
-    FHashList.Count := AValue;
-end;
-
-function TFPHashObjectList.GetItem(Index: Integer): TObject;
-begin
-  Result := TObject(FHashList[Index]);
-end;
-
-procedure TFPHashObjectList.SetItem(Index: Integer; AObject: TObject);
-begin
-  if OwnsObjects then
-    TObject(FHashList[Index]).Free;
-  FHashList[index] := AObject;
-end;
-
-procedure TFPHashObjectList.SetCapacity(NewCapacity: Integer);
-begin
-  FHashList.Capacity := NewCapacity;
-end;
-
-function TFPHashObjectList.GetCapacity: integer;
-begin
-  Result := FHashList.Capacity;
-end;
-
-function TFPHashObjectList.Add(const AName:shortstring;AObject: TObject): Integer;
-begin
-  Result := FHashList.Add(AName,AObject);
-end;
-
-function TFPHashObjectList.NameOfIndex(Index: Integer): shortstring;
-begin
-  Result := FHashList.NameOfIndex(Index);
-end;
-
-function TFPHashObjectList.HashOfIndex(Index: Integer): LongWord;
-begin
-  Result := FHashList.HashOfIndex(Index);
-end;
-
-procedure TFPHashObjectList.Delete(Index: Integer);
-begin
-  if OwnsObjects then
-    TObject(FHashList[Index]).Free;
-  FHashList.Delete(Index);
-end;
-
-function TFPHashObjectList.Expand: TFPHashObjectList;
-begin
-  FHashList.Expand;
-  Result := Self;
-end;
-
-function TFPHashObjectList.Extract(Item: TObject): TObject;
-begin
-  Result := TObject(FHashList.Extract(Item));
-end;
-
-function TFPHashObjectList.Remove(AObject: TObject): Integer;
-begin
-  Result := IndexOf(AObject);
-  if (Result <> -1) then
-    begin
-      if OwnsObjects then
-        TObject(FHashList[Result]).Free;
-      FHashList.Delete(Result);
-    end;
-end;
-
-function TFPHashObjectList.IndexOf(AObject: TObject): Integer;
-begin
-  Result := FHashList.IndexOf(Pointer(AObject));
-end;
-
-
-function TFPHashObjectList.Find(const s:shortstring): TObject;
-begin
-  result:=TObject(FHashList.Find(s));
-end;
-
-
-function TFPHashObjectList.FindIndexOf(const s:shortstring): Integer;
-begin
-  result:=FHashList.FindIndexOf(s);
-end;
-
-
-function TFPHashObjectList.FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
-begin
-  Result:=TObject(FHashList.FindWithHash(AName,AHash));
-end;
-
-
-function TFPHashObjectList.Rename(const AOldName,ANewName:shortstring): Integer;
-begin
-  Result:=FHashList.Rename(AOldName,ANewName);
-end;
-
-
-function TFPHashObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
-var
-  I : Integer;
-begin
-  I:=AStartAt;
-  Result:=-1;
-  If AExact then
-    while (I<Count) and (Result=-1) do
-      If Items[i].ClassType=AClass then
-        Result:=I
-      else
-        Inc(I)
-  else
-    while (I<Count) and (Result=-1) do
-      If Items[i].InheritsFrom(AClass) then
-        Result:=I
-      else
-        Inc(I);
-end;
-
-
-procedure TFPHashObjectList.Pack;
-begin
-  FHashList.Pack;
-end;
-
-
-procedure TFPHashObjectList.ShowStatistics;
-begin
-  FHashList.ShowStatistics;
-end;
-
-
-procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
-begin
-  FHashList.ForEachCall(TListCallBack(proc2call),arg);
-end;
-
-
-procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
-begin
-  FHashList.ForEachCall(TListStaticCallBack(proc2call),arg);
-end;
-
-
-{ ---------------------------------------------------------------------
-    Hash support, by Dean Zobec
-  ---------------------------------------------------------------------}
-
-{ Default hash function }
-
-function RSHash(const S: string; const TableSize: Longword): Longword;
-const
-  b = 378551;
-var
-  a: Longword;
-  i: Longword;
-begin
- a := 63689;
- Result := 0;
- if length(s)>0 then
-   for i := 1 to Length(S) do
-   begin
-     Result := Result * a + Ord(S[i]);
-     a := a * b;
-   end;
- Result := (Result and $7FFFFFFF) mod TableSize;
-end;
-
-{ THTNode }
-
-constructor THTCustomNode.CreateWith(const AString: string);
-begin
-  inherited Create;
-  FKey := AString;
-end;
-
-function THTCustomNode.HasKey(const AKey: string): boolean;
-begin
-  if Length(AKey) <> Length(FKey) then
-  begin
-    Result := false;
-    exit;
-  end
-  else
-    Result := CompareMem(PChar(FKey), PChar(AKey), length(AKey));
-end;
-
-{ TFPCustomHashTable }
-
-constructor TFPCustomHashTable.Create;
-begin
-  CreateWith(196613,@RSHash);
-end;
-
-constructor TFPCustomHashTable.CreateWith(AHashTableSize: Longword;
-  aHashFunc: THashFunction);
-begin
-  Inherited Create;
-  FHashTable := TFPObjectList.Create(True);
-  HashTableSize := AHashTableSize;
-  FHashFunction := aHashFunc;
-end;
-
-destructor TFPCustomHashTable.Destroy;
-begin
-  FHashTable.Free;
-  inherited Destroy;
-end;
-
-function TFPCustomHashTable.GetDensity: Longword;
-begin
-  Result := FHashTableSize - VoidSlots
-end;
-
-function TFPCustomHashTable.GetNumberOfCollisions: Longword;
-begin
-  Result := FCount -(FHashTableSize - VoidSlots)
-end;
-
-procedure TFPCustomHashTable.SetHashTableSize(const Value: Longword);
-var
-  i: Longword;
-  newSize: Longword;
-begin
-  if Value <> FHashTableSize then
-  begin
-    i := 0;
-    while (PRIMELIST[i] < Value) and (i < 27) do
-     inc(i);
-    newSize := PRIMELIST[i];
-    if Count = 0 then
-    begin
-      FHashTableSize := newSize;
-      InitializeHashTable;
-    end
-    else
-      ChangeTableSize(newSize);
-  end;
-end;
-
-procedure TFPCustomHashTable.InitializeHashTable;
-var
-  i: LongWord;
-begin
-  if FHashTableSize>0 Then
-    for i := 0 to FHashTableSize-1 do
-     FHashTable.Add(nil);
-  FCount := 0;
-end;
-
-procedure TFPCustomHashTable.ChangeTableSize(const ANewSize: Longword);
-var
-  SavedTable: TFPObjectList;
-  SavedTableSize: Longword;
-  i, j: Longword;
-  temp: THTCustomNode;
-begin
-  SavedTable := FHashTable;
-  SavedTableSize := FHashTableSize;
-  FHashTableSize := ANewSize;
-  FHashTable := TFPObjectList.Create(True);
-  InitializeHashTable;
-  If SavedTableSize>0 Then
-    for i := 0 to SavedTableSize-1 do
-    begin
-      if Assigned(SavedTable[i]) then
-      for j := 0 to TFPObjectList(SavedTable[i]).Count -1 do
-      begin
-        temp := THTCustomNode(TFPObjectList(SavedTable[i])[j]);
-        AddNode(temp);
-      end;
-    end;
-  SavedTable.Free;
-end;
-
-procedure TFPCustomHashTable.SetHashFunction(AHashFunction: THashFunction);
-begin
-  if IsEmpty then
-    FHashFunction := AHashFunction
-  else
-    raise Exception.Create(NotEmptyMsg);
-end;
-
-function TFPCustomHashTable.Find(const aKey: string): THTCustomNode;
-var
-  hashCode: Longword;
-  chn: TFPObjectList;
-  i: Longword;
-begin
-  hashCode := FHashFunction(aKey, FHashTableSize);
-  chn := Chain(hashCode);
-  if Assigned(chn) then
-  begin
-    if chn.count>0 then
-     for i := 0 to chn.Count - 1 do
-      if THTCustomNode(chn[i]).HasKey(aKey) then
-      begin
-        result := THTCustomNode(chn[i]);
-        exit;
-      end;
-  end;
-  Result := nil;
-end;
-
-Function TFPCustomHashTable.FindChainForAdd(Const aKey : String) : TFPObjectList;
-
-var
-  hashCode: Longword;
-  i: Longword;
-
-begin
-  hashCode := FHashFunction(aKey, FHashTableSize);
-  Result := Chain(hashCode);
-  if Assigned(Result)  then
-    begin
-    if Result.count>0 then
-      for i := 0 to Result.Count - 1 do
-        if THTCustomNode(Result[i]).HasKey(aKey) then
-          Raise EDuplicate.CreateFmt(DuplicateMsg, [aKey]);
-    end
-  else
-    begin
-    FHashTable[hashcode] := TFPObjectList.Create(true);
-    Result := Chain(hashcode);
-    end;
-  inc(FCount);
-end;
-
-
-procedure TFPCustomHashTable.Delete(const aKey: string);
-var
-  hashCode: Longword;
-  chn: TFPObjectList;
-  i: Longword;
-begin
-  hashCode := FHashFunction(aKey, FHashTableSize);
-  chn := Chain(hashCode);
-  if Assigned(chn) then
-  begin
-    if chn.count>0 then
-    for i := 0 to chn.Count - 1 do
-      if THTCustomNode(chn[i]).HasKey(aKey) then
-      begin
-        chn.Delete(i);
-        dec(FCount);
-        exit;
-      end;
-  end;
-  raise EKeyNotFound.CreateFmt(KeyNotFoundMsg, ['Delete', aKey]);
-end;
-
-function TFPCustomHashTable.IsEmpty: boolean;
-begin
-  Result := (FCount = 0);
-end;
-
-function TFPCustomHashTable.Chain(const index: Longword): TFPObjectList;
-begin
-  Result := TFPObjectList(FHashTable[index]);
-end;
-
-function TFPCustomHashTable.GetVoidSlots: Longword;
-var
-  i: Longword;
-  num: Longword;
-begin
-  num := 0;
-  if FHashTableSize>0 Then
-    for i:= 0 to FHashTableSize-1 do
-      if Not Assigned(Chain(i)) then
-        inc(num);
-  result := num;
-end;
-
-function TFPCustomHashTable.GetLoadFactor: double;
-begin
-  Result := Count / FHashTableSize;
-end;
-
-function TFPCustomHashTable.GetAVGChainLen: double;
-begin
-  result := Count / (FHashTableSize - VoidSlots);
-end;
-
-function TFPCustomHashTable.GetMaxChainLength: Longword;
-var
-  i: Longword;
-begin
-  Result := 0;
-  if FHashTableSize>0 Then
-   for i := 0 to FHashTableSize-1 do
-      if ChainLength(i) > Result then
-        Result := ChainLength(i);
-end;
-
-function TFPCustomHashTable.FindOrCreateNew(const aKey: string): THTCustomNode;
-var
-  hashCode: Longword;
-  chn: TFPObjectList;
-  i: Longword;
-begin
-  hashCode := FHashFunction(aKey, FHashTableSize);
-  chn := Chain(hashCode);
-  if Assigned(chn)  then
-  begin
-    if chn.count>0 then
-     for i := 0 to chn.Count - 1 do
-      if THTCustomNode(chn[i]).HasKey(aKey) then
-        begin
-          Result := THTNode(chn[i]);
-          exit;
-        end
-  end
-  else
-    begin
-      FHashTable[hashcode] := TFPObjectList.Create(true);
-      chn := Chain(hashcode);
-    end;
-  inc(FCount);
-  Result := CreateNewNode(aKey);
-  chn.Add(Result);
-end;
-
-function TFPCustomHashTable.ChainLength(const ChainIndex: Longword): Longword;
-begin
-  if Assigned(Chain(ChainIndex)) then
-    Result := Chain(ChainIndex).Count
-  else
-    Result := 0;
-end;
-
-procedure TFPCustomHashTable.Clear;
-var
-  i: Longword;
-begin
-  if FHashTableSize>0 Then
-    for i := 0 to FHashTableSize - 1 do
-      begin
-        if Assigned(Chain(i)) then
-          Chain(i).Clear;
-      end;
-  FCount := 0;
-end;
-
-
-
-{ TFPDataHashTable }
-
-procedure TFPDataHashTable.Add(const aKey: string; aItem: pointer);
-var
-  chn: TFPObjectList;
-  NewNode: THtDataNode;
-begin
-  chn:=FindChainForAdd(akey);
-  NewNode := THtDataNode(CreateNewNode(aKey));
-  NewNode.Data := aItem;
-  chn.Add(NewNode);
-end;
-
-function TFPDataHashTable.GetData(const Index: string): Pointer;
-var
-  node: THTDataNode;
-begin
-  node := THTDataNode(Find(Index));
-  if Assigned(node) then
-    Result := node.Data
-  else
-    Result := nil;
-end;
-
-procedure TFPDataHashTable.SetData(const index: string; const AValue: Pointer);
-begin
-  THTDataNode(FindOrCreateNew(index)).Data := AValue;
-end;
-
-Function TFPDataHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
-
-begin
-  Result:=THTDataNode.CreateWith(aKey);
-end;
-
-function TFPDataHashTable.ForEachCall(aMethod: TDataIteratorMethod): THTDataNode;
-var
-  i, j: Longword;
-  continue: boolean;
-begin
-  Result := nil;
-  continue := true;
-  if FHashTableSize>0 then
-   for i := 0 to FHashTableSize-1 do
-    begin
-      if assigned(Chain(i)) then
-      begin
-       if chain(i).count>0 then
-        for j := 0 to Chain(i).Count-1 do
-        begin
-          aMethod(THTDataNode(Chain(i)[j]).Data, THTDataNode(Chain(i)[j]).Key, continue);
-          if not continue then
-          begin
-            Result := THTDataNode(Chain(i)[j]);
-            Exit;
-          end;
-        end;
-      end;
-    end;
-end;
-
-Procedure TFPDataHashTable.AddNode(ANode : THTCustomNode);
-
-begin
-  With THTDataNode(ANode) do
-    Add(Key,Data);
-end;
-
-{ TFPStringHashTable }
-
-Procedure TFPStringHashTable.AddNode(ANode : THTCustomNode);
-
-begin
-  With THTStringNode(ANode) do
-    Add(Key,Data);
-end;
-
-function TFPStringHashTable.GetData(const Index: string): String;
-var
-  node: THTStringNode;
-begin
-  node := THTStringNode(Find(Index));
-  if Assigned(node) then
-    Result := node.Data
-  else
-    Result := '';
-end;
-
-procedure TFPStringHashTable.SetData(const index, AValue: string);
-begin
-  THTStringNode(FindOrCreateNew(index)).Data := AValue;
-end;
-
-procedure TFPStringHashTable.Add(const aKey, aItem: string);
-var
-  chn: TFPObjectList;
-  NewNode: THtStringNode;
-
-begin
-  chn:=FindChainForAdd(akey);
-  NewNode := THtStringNode(CreateNewNode(aKey));
-  NewNode.Data := aItem;
-  chn.Add(NewNode);
-end;
-
-Function TFPStringHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
-
-begin
-  Result:=THTStringNode.CreateWith(aKey);
-end;
-
-
-function TFPStringHashTable.ForEachCall(aMethod: TStringIteratorMethod): THTStringNode;
-var
-  i, j: Longword;
-  continue: boolean;
-begin
-  Result := nil;
-  continue := true;
-  if FHashTableSize>0 then
-   for i := 0 to FHashTableSize-1 do
-    begin
-      if assigned(Chain(i)) then
-      begin
-       if chain(i).count>0 then
-        for j := 0 to Chain(i).Count-1 do
-        begin
-          aMethod(THTStringNode(Chain(i)[j]).Data, THTStringNode(Chain(i)[j]).Key, continue);
-          if not continue then
-          begin
-            Result := THTStringNode(Chain(i)[j]);
-            Exit;
-          end;
-        end;
-      end;
-    end;
-end;
-
-{ TFPObjectHashTable }
-
-Procedure TFPObjectHashTable.AddNode(ANode : THTCustomNode);
-
-begin
-  With THTObjectNode(ANode) do
-    Add(Key,Data);
-end;
-
-function TFPObjectHashTable.GetData(const Index: string): TObject;
-var
-  node: THTObjectNode;
-begin
-  node := THTObjectNode(Find(Index));
-  if Assigned(node) then
-    Result := node.Data
-  else
-    Result := Nil;
-end;
-
-procedure TFPObjectHashTable.SetData(const index : string; AObject : TObject);
-begin
-  THTObjectNode(FindOrCreateNew(index)).Data := AObject;
-end;
-
-procedure TFPObjectHashTable.Add(const aKey: string; AItem : TObject);
-var
-  chn: TFPObjectList;
-  NewNode: THTObjectNode;
-
-begin
-  chn:=FindChainForAdd(akey);
-  NewNode := THTObjectNode(CreateNewNode(aKey));
-  NewNode.Data := aItem;
-  chn.Add(NewNode);
-end;
-
-Function TFPObjectHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
-
-begin
-  If OwnsObjects then
-    Result:=THTOwnedObjectNode.CreateWith(aKey)
-  else
-    Result:=THTObjectNode.CreateWith(aKey);
-end;
-
-
-function TFPObjectHashTable.ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode;
-var
-  i, j: Longword;
-  continue: boolean;
-begin
-  Result := nil;
-  continue := true;
-  if FHashTableSize>0 then
-   for i := 0 to FHashTableSize-1 do
-    begin
-      if assigned(Chain(i)) then
-      begin
-       if chain(i).count>0 then
-        for j := 0 to Chain(i).Count-1 do
-        begin
-          aMethod(THTObjectNode(Chain(i)[j]).Data, THTObjectNode(Chain(i)[j]).Key, continue);
-          if not continue then
-          begin
-            Result := THTObjectNode(Chain(i)[j]);
-            Exit;
-          end;
-        end;
-      end;
-    end;
-end;
-
-constructor TFPObjectHashTable.Create(AOwnsObjects : Boolean = True);
-
-begin
-  Inherited Create;
-  FOwnsObjects:=AOwnsObjects;
-end;
-
-constructor TFPObjectHashTable.CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True);
-
-begin
-  Inherited CreateWith(AHashTableSize,AHashFunc);
-  FOwnsObjects:=AOwnsObjects;
-end;
-
-Destructor THTOwnedObjectNode.Destroy;
-
-begin
-  FreeAndNil(FData);
-  Inherited;
-end;
-
-end.

+ 0 - 363
utils/fppkg/fcl20/streamcoll.pp

@@ -1,363 +0,0 @@
-{
-    This file is part of the Free Component Library (FCL)
-    Copyright (c) 1999-2000 by the Free Pascal development team
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-
-{$ifndef ver2_0}
-  {$fatal This unit is only for compiling with 2.0.x, use the streamcoll from the FCL}
-{$endif}
-
-{$mode objfpc}
-{$h+}
-unit streamcoll;
-
-interface
-
-uses
-  Classes,SysUtils;
-
-type
-  TStreamCollectionItem = Class(TCollectionItem)
-  Protected
-    Procedure WriteInteger(S : TStream; AValue : Integer);
-    Procedure WriteBoolean(S : TStream; AValue : Boolean);
-    Procedure WriteString(S : TStream; AValue : String);
-    Procedure WriteCurrency(S : TStream; AValue : Currency);
-    Procedure WriteDateTime(S : TStream; AValue : TDateTime);
-    Procedure WriteFloat(S : TStream; AValue : Double);
-    Function ReadInteger(S : TStream) : Integer;
-    Function ReadBoolean(S : TStream) : Boolean;
-    Function ReadString(S : TStream) : String;
-    Function ReadCurrency(S : TStream) : Currency;
-    Function ReadDateTime(S : TStream) : TDateTime;
-    Function ReadFloat(S : TStream) : Double;
-    Procedure LoadFromStream(S : TStream; Streamversion : Integer); virtual; abstract;
-    Procedure SaveToStream(S : TStream); virtual; abstract;
-  end;
-
-  TStreamCollection = Class(TCollection)
-  Private
-    FStreaming : Boolean;
-  Protected
-    Procedure WriteInteger(S : TStream; AValue : Integer);
-    Procedure WriteBoolean(S : TStream; AValue : Boolean);
-    Procedure WriteString(S : TStream; AValue : String);
-    Procedure WriteCurrency(S : TStream; AValue : Currency);
-    Procedure WriteDateTime(S : TStream; AValue : TDateTime);
-    Procedure WriteFloat(S : TStream; AValue : Double);
-    Function ReadInteger(S : TStream) : Integer;
-    Function ReadBoolean(S : TStream) : Boolean;
-    Function ReadString(S : TStream) : String;
-    Function ReadCurrency(S : TStream) : Currency;
-    Function ReadDateTime(S : TStream) : TDateTime;
-    Function ReadFloat(S : TStream) : Double;
-    Procedure DoSaveToStream(S : TStream); virtual;
-    Function CurrentStreamVersion : Integer; Virtual;
-    Procedure DoLoadFromStream(S : TStream; Streamversion : Integer); virtual;
-  Public
-    Procedure LoadFromStream(S : TStream);
-    Procedure SaveToStream(S : TStream);
-    Property Streaming : Boolean Read FStreaming;
-  end;
-
-
-  EStreamColl = Class(Exception);
-
-Procedure ColWriteInteger(S : TStream; AValue : Integer);
-Procedure ColWriteBoolean(S : TStream; AValue : Boolean);
-Procedure ColWriteString(S : TStream; AValue : String);
-Procedure ColWriteCurrency(S : TStream; AValue : Currency);
-Procedure ColWriteDateTime(S : TStream; AValue : TDateTime);
-Procedure ColWriteFloat(S : TStream; AValue : Double);
-Function ColReadInteger(S : TStream) : Integer;
-Function ColReadBoolean(S : TStream) : Boolean;
-Function ColReadString(S : TStream) : String;
-Function ColReadCurrency(S : TStream) : Currency;
-Function ColReadDateTime(S : TStream) : TDateTime;
-Function ColReadFloat(S : TStream) : Double;
-
-implementation
-
-Resourcestring
-  SErrIllegalStreamVersion = 'Illegal stream version: %d > %d.';
-
-Procedure ColWriteInteger(S : TStream; AValue : Integer);
-
-begin
-  S.WriteBuffer(AValue,SizeOf(Integer));
-end;
-
-Procedure ColWriteBoolean(S : TStream; AValue : Boolean);
-
-begin
-  ColWriteInteger(S,Ord(AValue));
-end;
-
-Procedure ColWriteString(S : TStream; AValue : String);
-
-Var
-  L : Integer;
-
-begin
-  L:=Length(AValue);
-  ColWriteInteger(S,L);
-  If (L>0) then
-    S.WriteBuffer(AValue[1],L);
-end;
-
-Procedure ColWriteCurrency(S : TStream; AValue : Currency);
-
-begin
-  S.WriteBuffer(AValue,SizeOf(Currency));
-end;
-
-Procedure ColWriteDateTime(S : TStream; AValue : TDateTime);
-
-begin
-  S.WriteBuffer(AValue,SizeOf(TDateTime));
-end;
-
-Procedure ColWriteFloat(S : TStream; AValue : Double);
-
-begin
-  S.WriteBuffer(AValue,SizeOf(Double));
-end;
-
-Function ColReadInteger(S : TStream) : Integer;
-
-begin
-  S.ReadBuffer(Result,SizeOf(Integer));
-end;
-
-Function ColReadBoolean(S : TStream) : Boolean;
-
-Var
-  I : Integer;
-
-begin
-  S.ReadBuffer(I,SizeOf(Integer));
-  Result:=(I<>0);
-end;
-
-Function ColReadString(S : TStream) : String;
-
-Var
-  L : Integer;
-
-begin
-  L:=ColReadInteger(S);
-  SetLength(Result,L);
-  If (L>0) then
-    S.ReadBuffer(Result[1],L);
-end;
-
-Function ColReadCurrency(S : TStream) : Currency;
-
-begin
-  S.ReadBuffer(Result,SizeOf(Currency));
-end;
-
-Function ColReadDateTime(S : TStream) : TDateTime;
-
-begin
-  S.ReadBuffer(Result,SizeOf(TDateTime));
-end;
-
-Function ColReadFloat(S : TStream) : Double;
-
-begin
-  S.ReadBuffer(Result,SizeOf(Double));
-end;
-
-{ TStreamCollectionItem }
-
-function TStreamCollectionItem.ReadBoolean(S: TStream): Boolean;
-begin
-  Result:=ColReadBoolean(S);
-end;
-
-function TStreamCollectionItem.ReadCurrency(S: TStream): Currency;
-begin
-  Result:=ColReadCurrency(S);
-end;
-
-function TStreamCollectionItem.ReadDateTime(S: TStream): TDateTime;
-begin
-  Result:=ColReadDateTime(S);
-end;
-
-function TStreamCollectionItem.ReadFloat(S: TStream): Double;
-begin
-  Result:=ColReadFloat(S);
-end;
-
-function TStreamCollectionItem.ReadInteger(S: TStream): Integer;
-begin
-  Result:=ColReadinteger(S);
-end;
-
-function TStreamCollectionItem.ReadString(S: TStream): String;
-begin
-  Result:=ColReadString(S);
-end;
-
-procedure TStreamCollectionItem.WriteBoolean(S: TStream; AValue: Boolean);
-begin
-  ColWriteBoolean(S,AValue);
-end;
-
-procedure TStreamCollectionItem.WriteCurrency(S: TStream;
-  AValue: Currency);
-begin
-  ColWriteCurrency(S,AValue);
-end;
-
-procedure TStreamCollectionItem.WriteDateTime(S: TStream;
-  AValue: TDateTime);
-begin
-  ColWriteDateTime(S,AValue);
-end;
-
-procedure TStreamCollectionItem.WriteFloat(S: TStream; AValue: Double);
-begin
-  ColWriteFloat(S,AValue);
-end;
-
-procedure TStreamCollectionItem.WriteInteger(S: TStream; AValue: Integer);
-begin
-  ColWriteInteger(S,AValue);
-end;
-
-procedure TStreamCollectionItem.WriteString(S: TStream; AValue: String);
-begin
-  ColWriteString(S,AValue);
-end;
-
-{ TStreamCollection }
-
-function TStreamCollection.CurrentStreamVersion: Integer;
-begin
-  Result:=0;
-end;
-
-procedure TStreamCollection.DoLoadFromStream(S: TStream;
-  Streamversion: Integer);
-begin
-  If (Streamversion>CurrentStreamVersion) then
-    Raise EStreamColl.CreateFmt(SErrIllegalStreamVersion,[Streamversion,CurrentStreamVersion]);
-end;
-
-procedure TStreamCollection.DoSaveToStream(S: TStream);
-begin
-  // Do nothing.
-end;
-
-procedure TStreamCollection.LoadFromStream(S: TStream);
-
-Var
-  I,V,C : Integer;
-
-begin
-  FStreaming:=True;
-  Try
-    V:=ReadInteger(S);
-    DoLoadFromStream(S,V);
-    Clear;
-    C:=ReadInteger(S);
-    For I:=1 to C do
-      With Add as TStreamCollectionItem do
-        LoadFromStream(S,V);
-  Finally
-    FStreaming:=False;
-  end;
-end;
-
-function TStreamCollection.ReadBoolean(S: TStream): Boolean;
-begin
-  Result:=ColReadBoolean(S);
-end;
-
-function TStreamCollection.ReadCurrency(S: TStream): Currency;
-begin
-  Result:=ColReadCurrency(S);
-end;
-
-function TStreamCollection.ReadDateTime(S: TStream): TDateTime;
-begin
-  Result:=ColReadDateTime(S);
-end;
-
-function TStreamCollection.ReadFloat(S: TStream): Double;
-begin
-  Result:=ColReadFloat(S);
-end;
-
-function TStreamCollection.ReadInteger(S: TStream): Integer;
-begin
-  Result:=ColReadInteger(S);
-end;
-
-function TStreamCollection.ReadString(S: TStream): String;
-begin
-  Result:=ColReadString(S);
-end;
-
-procedure TStreamCollection.SaveToStream(S: TStream);
-
-Var
-  I : Integer;
-
-begin
-  FStreaming:=True;
-  Try
-    WriteInteger(S,CurrentStreamVersion);
-    DoSaveToStream(S);
-    WriteInteger(S,Count);
-    For I:=0 to Count-1 do
-      With TStreamCollectionItem(Items[i]) do
-        SaveToStream(S);
-  Finally
-    FStreaming:=False;
-  end;
-end;
-
-procedure TStreamCollection.WriteBoolean(S: TStream; AValue: Boolean);
-begin
-  ColWriteBoolean(S,AValue);
-end;
-
-procedure TStreamCollection.WriteCurrency(S: TStream; AValue: Currency);
-begin
-  ColWriteCurrency(S,AValue);
-end;
-
-procedure TStreamCollection.WriteDateTime(S: TStream; AValue: TDateTime);
-begin
-  ColWriteDateTime(S,AValue);
-end;
-
-procedure TStreamCollection.WriteFloat(S: TStream; AValue: Double);
-begin
-  ColWriteFloat(S,AValue);
-end;
-
-procedure TStreamCollection.WriteInteger(S: TStream; AValue: Integer);
-begin
-  ColWriteInteger(S,AValue);
-end;
-
-procedure TStreamCollection.WriteString(S: TStream; AValue: String);
-begin
-  ColWriteString(S,AValue);
-end;
-
-
-end.

+ 0 - 425
utils/fppkg/fcl20/uriparser.pp

@@ -1,425 +0,0 @@
-{
-    This file is part of the Free Pascal run time library.
-    Copyright (c) 2003 by the Free Pascal development team
-    Original author: Sebastian Guenther
-
-    Unit to parse complete URI in its parts or to reassemble an URI
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-{$IFDEF FPC}
-{$MODE objfpc}
-{$H+}
-{$ENDIF}
-
-unit URIParser;
-
-interface
-
-type
-  TURI = record
-    Protocol: String;
-    Username: String;
-    Password: String;
-    Host: String;
-    Port: Word;
-    Path: String;
-    Document: String;
-    Params: String;
-    Bookmark: String;
-    HasAuthority: Boolean;
-  end;
-
-function EncodeURI(const URI: TURI): String;
-function ParseURI(const URI: String):  TURI; overload;
-function ParseURI(const URI, DefaultProtocol: String; DefaultPort: Word):  TURI; overload;
-
-function ResolveRelativeURI(const BaseUri, RelUri: WideString;
-  out ResultUri: WideString): Boolean; overload;
-
-function ResolveRelativeURI(const BaseUri, RelUri: UTF8String;
-  out ResultUri: UTF8String): Boolean; overload;
-
-function URIToFilename(const URI: string; out Filename: string): Boolean;
-function FilenameToURI(const Filename: string): string;
-
-function IsAbsoluteURI(const UriReference: string): Boolean;
-
-implementation
-
-uses SysUtils;
-
-const
-  GenDelims = [':', '/', '?', '#', '[', ']', '@'];
-  SubDelims = ['!', '$', '&', '''', '(', ')', '*', '+', ',', ';', '='];
-  ALPHA = ['A'..'Z', 'a'..'z'];
-  DIGIT = ['0'..'9'];
-  Unreserved = ALPHA + DIGIT + ['-', '.', '_', '~'];
-  ValidPathChars = Unreserved + SubDelims + ['@', ':', '/'];
-
-function Escape(const s: String; const Allowed: TSysCharSet): String;
-var
-  i: Integer;
-begin
-  SetLength(Result, 0);
-  for i := 1 to Length(s) do
-    if not (s[i] in Allowed) then
-      Result := Result + '%' + IntToHex(ord(s[i]), 2)
-    else
-      Result := Result + s[i];
-end;
-
-function EncodeURI(const URI: TURI): String;
-// ! if no scheme then first colon in path should be escaped
-begin
-  SetLength(Result, 0);
-  if Length(URI.Protocol) > 0 then
-    Result := LowerCase(URI.Protocol) + ':';
-  if URI.HasAuthority then
-  begin
-    Result := Result + '//';
-    if Length(URI.Username) > 0 then
-    begin
-      Result := Result + URI.Username;
-      if Length(URI.Password) > 0 then
-        Result := Result + ':' + URI.Password;
-      Result := Result + '@';
-    end;
-    Result := Result + URI.Host;
-  end;
-  if URI.Port <> 0 then
-    Result := Result + ':' + IntToStr(URI.Port);
-  Result := Result + Escape(URI.Path, ValidPathChars);
-  if Length(URI.Document) > 0 then
-  begin
-    if (Length(URI.Path) > 0) and ((Length(Result) = 0) or (Result[Length(Result)] <> '/')) then
-      Result := Result + '/';
-    Result := Result + Escape(URI.Document, ValidPathChars);
-  end;
-  if Length(URI.Params) > 0 then
-    Result := Result + '?' + Escape(URI.Params, ValidPathChars);
-  if Length(URI.Bookmark) > 0 then
-    Result := Result + '#' + Escape(URI.Bookmark, ValidPathChars);
-end;
-
-function ParseURI(const URI: String):  TURI;
-begin
-  Result := ParseURI(URI, '', 0);
-end;
-
-function HexValue(c: Char): Integer;
-begin
-  case c of
-    '0'..'9': Result := ord(c) - ord('0');
-    'A'..'F': Result := ord(c) - (ord('A') - 10);
-    'a'..'f': Result := ord(c) - (ord('a') - 10);
-  else
-    Result := 0;
-  end;
-end;
-
-function Unescape(const s: String): String;
-var
-  i, RealLength: Integer;
-begin
-  SetLength(Result, Length(s));
-  i := 1;
-  RealLength := 0;
-  while i <= Length(s) do
-  begin
-    Inc(RealLength);
-    if s[i] = '%' then
-    begin
-      Result[RealLength] := Chr(HexValue(s[i + 1]) shl 4 or HexValue(s[i + 2]));
-      Inc(i, 3);
-    end else
-    begin
-      Result[RealLength] := s[i];
-      Inc(i);
-    end;
-  end;
-  SetLength(Result, RealLength);
-end;
-
-function ParseURI(const URI, DefaultProtocol: String; DefaultPort: Word):  TURI;
-var
-  s, Authority: String;
-  i: Integer;
-begin
-  Result.Protocol := LowerCase(DefaultProtocol);
-  Result.Port := DefaultPort;
-
-  s := URI;
-
-  // Extract scheme
-
-  for i := 1 to Length(s) do
-    if s[i] = ':' then
-    begin
-      Result.Protocol := Copy(s, 1, i - 1);
-      s := Copy(s, i + 1, MaxInt);
-      break;
-    end
-    else
-      if not (((i=1) and (s[i] in ALPHA)) or (s[i] in ALPHA + DIGIT + ['+', '-', '.'])) then
-        break;
-
-  // Extract the bookmark
-
-  i := LastDelimiter('#', s);
-  if i > 0 then
-  begin
-    Result.Bookmark := Unescape(Copy(s, i + 1, MaxInt));
-    s := Copy(s, 1, i - 1);
-  end;
-
-  // Extract the params
-
-  i := LastDelimiter('?', s);
-  if i > 0 then
-  begin
-    Result.Params := Unescape(Copy(s, i + 1, MaxInt));
-    s := Copy(s, 1, i - 1);
-  end;
-
-  // extract authority
-
-  if (Length(s) > 1) and (s[1] = '/') and (s[2] = '/') then
-  begin
-    i := 3;
-    while (i <= Length(s)) and (s[i] <> '/') do
-      Inc(i);
-    Authority := Copy(s, 3, i-3);
-    s := Copy(s, i, MaxInt);
-    Result.HasAuthority := True;    // even if Authority is empty
-  end
-  else
-  begin
-    Result.HasAuthority := False;
-    Authority := '';
-  end;
-
-  // now s is 'hier-part' per RFC3986
-  // Extract the document name (nasty...)
-
-  for i := Length(s) downto 1 do
-    if s[i] = '/' then
-    begin
-      Result.Document := Unescape(Copy(s, i + 1, Length(s)));
-      if (Result.Document <> '.') and (Result.Document <> '..') then
-        s := Copy(s, 1, i)
-      else
-        Result.Document := '';
-      break;
-    end else if s[i] = ':' then
-      break
-    else if i = 1 then
-    begin
-      Result.Document := Unescape(s);
-      if (Result.Document <> '.') and (Result.Document <> '..') then
-        s := ''
-      else
-        Result.Document := '';
-      // break - not needed, last iteration
-    end;
-
-  // Everything left is a path
-
-  Result.Path := Unescape(s);
-
-  // Extract the port number
-
-  i := LastDelimiter(':@', Authority);
-  if (i > 0) and (Authority[i] = ':') then
-  begin
-    Result.Port := StrToInt(Copy(Authority, i + 1, MaxInt));
-    Authority := Copy(Authority, 1, i - 1);
-  end;
-
-  // Extract the hostname
-
-  i := Pos('@', Authority);
-  if i > 0 then
-  begin
-    Result.Host := Copy(Authority, i+1, MaxInt);
-    Delete(Authority, i, MaxInt);
-
-    // Extract username and password
-    if Length(Authority) > 0 then
-    begin
-      i := Pos(':', Authority);
-      if i = 0 then
-        Result.Username := Authority
-      else
-      begin
-        Result.Username := Copy(Authority, 1, i - 1);
-        Result.Password := Copy(Authority, i + 1, MaxInt);
-      end;
-    end;
-  end
-  else
-    Result.Host := Authority;
-end;
-
-procedure RemoveDotSegments(var s: string);
-var
-  Cur, Prev: Integer;
-begin
-  Prev := Pos('/', s);
-  while (Prev > 0) and (Prev < Length(s)) do
-  begin
-    Cur := Prev+1;
-    while (Cur <= Length(s)) and (s[Cur] <> '/') do
-      Inc(Cur);
-    if (Cur - Prev = 2) and (s[Prev+1] = '.') then
-      Delete(s, Prev+1, 2)
-    else if (Cur - Prev = 3) and (s[Prev+1] = '.') and (s[Prev+2] = '.') then
-    begin
-      while (Prev > 1) and (s[Prev-1] <> '/') do
-        Dec(Prev);
-      if Prev > 1 then
-        Dec(Prev);
-      Delete(s, Prev+1, Cur-Prev);
-    end
-    else
-      Prev := Cur;
-  end;
-end;
-
-// TODO: this probably must NOT percent-encode the result...
-function ResolveRelativeURI(const BaseUri, RelUri: UTF8String;
-  out ResultUri: UTF8String): Boolean;
-var
-  Base, Rel: TUri;
-begin
-  Base := ParseUri(BaseUri);
-  Rel := ParseUri(RelUri);
-
-  Result := (Base.Protocol <> '') or (Rel.Protocol <> '');
-  if not Result then
-    Exit;
-  with Rel do
-  begin
-    if (Path = '') and (Document = '') then
-    begin
-      if (Protocol = '') and (Host = '') then
-      begin
-        if Params <> '' then
-          Base.Params := Params;
-        Base.Bookmark := Bookmark;
-        ResultUri := EncodeUri(Base);
-        Exit;
-      end;
-    end;
-    if (Protocol <> '') then  // RelURI is absolute - return it...
-    begin
-      ResultUri := RelUri;
-      Exit;
-    end;
-    // Inherit protocol
-    Protocol := Base.Protocol;
-    if (Host = '') then   // TODO: or "not HasAuthority"?
-    begin
-      // Inherit Authority (host, port, username, password)
-      Host := Base.Host;
-      Port := Base.Port;
-      Username := Base.Username;
-      Password := Base.Password;
-      HasAuthority := Base.HasAuthority;
-      if (Path = '') or (Path[1] <> '/') then  // path is empty or relative
-        Path := Base.Path + Path;
-      RemoveDotSegments(Path);      
-    end;
-  end; // with
-  ResultUri := EncodeUri(Rel);
-end;
-
-function ResolveRelativeURI(const BaseUri, RelUri: WideString;
-  out ResultUri: WideString): Boolean;
-var
-  rslt: UTF8String;
-begin
-  Result := ResolveRelativeURI(UTF8Encode(BaseUri), UTF8Encode(RelUri), rslt);
-  if Result then
-    ResultURI := UTF8Decode(rslt);
-end;
-
-function URIToFilename(const URI: string; out Filename: string): Boolean;
-var
-  U: TURI;
-  I: Integer;
-begin
-  Result := False;
-  U := ParseURI(URI);
-  if SameText(U.Protocol, 'file') then
-  begin
-    if (Length(U.Path) > 2) and (U.Path[1] = '/') and (U.Path[3] = ':') then
-      Filename := Copy(U.Path, 2, MaxInt)
-    else
-      Filename := U.Path;
-    Filename := Filename + U.Document;
-    Result := True;
-  end
-  else
-    if U.Protocol = '' then  // fire and pray?
-    begin
-      Filename := U.Path + U.Document;
-      Result := True;
-    end;
-  if PathDelim <> '/' then
-  begin
-    I := Pos('/', Filename);
-    while I > 0 do
-    begin
-      Filename[I] := PathDelim;
-      I := Pos('/', Filename);
-    end;
-  end;
-end;
-
-function FilenameToURI(const Filename: string): string;
-var
-  I: Integer;
-begin
-  // TODO: seems implemented, but not tested well
-  Result := 'file://';
-  if (Length(Filename) > 2) and (Filename[1] <> PathDelim) and (Filename[2] = ':') then
-    Result := Result + '/';
-  Result := Result + Filename;
-  if PathDelim <> '/' then
-  begin
-    I := Pos(PathDelim, Result);
-    while I <> 0 do
-    begin
-      Result[I] := '/';
-      I := Pos(PathDelim, Result);
-    end;
-  end;
-end;
-
-
-function IsAbsoluteURI(const UriReference: string): Boolean;
-var
-  I: Integer;
-begin
-  Result := True;
-  for I := 1 to Length(UriReference) do
-  begin
-    if UriReference[I] = ':' then
-      Exit
-    else
-      if not (((I=1) and (UriReference[I] in ALPHA)) or
-         (UriReference[i] in ALPHA + DIGIT + ['+', '-', '.'])) then
-      Break;
-  end;
-  Result := False;
-end;
-
-
-end.

+ 0 - 1470
utils/fppkg/fcl20/zipper.pp

@@ -1,1470 +0,0 @@
-{
-    $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
-    This file is part of the Free Component Library (FCL)
-    Copyright (c) 1999-2000 by the Free Pascal development team
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-{$mode objfpc}
-{$h+}
-unit zipper;
-
-Interface
-
-Uses
-   SysUtils,Classes,Contnrs,ZStream;
-
-
-Const
-  { Signatures }
-{$ifdef FPC_BIG_ENDIAN}
-  END_OF_CENTRAL_DIR_SIGNATURE  = $504B0506;
-  LOCAL_FILE_HEADER_SIGNATURE   = $504B0304;
-  CENTRAL_FILE_HEADER_SIGNATURE = $504B0102;
-{$else FPC_BIG_ENDIAN}
-  END_OF_CENTRAL_DIR_SIGNATURE  = $06054B50;
-  LOCAL_FILE_HEADER_SIGNATURE   = $04034B50;
-  CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
-{$endif FPC_BIG_ENDIAN}
-
-Type
-   Local_File_Header_Type = Packed Record
-     Signature              :  LongInt;
-     Extract_Version_Reqd   :  Word;
-     Bit_Flag               :  Word;
-     Compress_Method        :  Word;
-     Last_Mod_Time          :  Word;
-     Last_Mod_Date          :  Word;
-     Crc32                  :  LongWord;
-     Compressed_Size        :  LongInt;
-     Uncompressed_Size      :  LongInt;
-     Filename_Length        :  Word;
-     Extra_Field_Length     :  Word;
-   end;
-
-  { Define the Central Directory record types }
-
-  Central_File_Header_Type = Packed Record
-    Signature            :  LongInt;
-    MadeBy_Version       :  Word;
-    Extract_Version_Reqd :  Word;
-    Bit_Flag             :  Word;
-    Compress_Method      :  Word;
-    Last_Mod_Time        :  Word;
-    Last_Mod_Date        :  Word;
-    Crc32                :  LongWord;
-    Compressed_Size      :  LongInt;
-    Uncompressed_Size    :  LongInt;
-    Filename_Length      :  Word;
-    Extra_Field_Length   :  Word;
-    File_Comment_Length  :  Word;
-    Starting_Disk_Num    :  Word;
-    Internal_Attributes  :  Word;
-    External_Attributes  :  LongInt;
-    Local_Header_Offset  :  LongInt;
-  End;
-
-  End_of_Central_Dir_Type =  Packed Record
-    Signature               :  LongInt;
-    Disk_Number             :  Word;
-    Central_Dir_Start_Disk  :  Word;
-    Entries_This_Disk       :  Word;
-    Total_Entries           :  Word;
-    Central_Dir_Size        :  LongInt;
-    Start_Disk_Offset       :  LongInt;
-    ZipFile_Comment_Length  :  Word;
-  end;
-
-Const
-  Crc_32_Tab : Array[0..255] of LongWord = (
-    $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
-    $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
-    $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
-    $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
-    $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
-    $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
-    $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
-    $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
-    $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
-    $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
-    $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
-    $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
-    $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
-    $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
-    $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
-    $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
-    $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
-    $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
-    $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
-    $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
-    $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
-    $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
-    $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
-    $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
-    $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
-    $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
-    $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
-    $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
-    $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
-    $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
-    $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
-    $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d
-  );
-
-Type
-
-  TZipItem   = Class(TObject)
-    Path : String;
-    Name : String;
-    Size : LongInt;
-    DateTime : TDateTime;
-    HdrPos : Longint;
-  end;
-
-  TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
-  TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
-  TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
-
-Type
-
-  { TCompressor }
-  TCompressor = Class(TObject)
-  Protected
-    FInFile     : TStream;        { I/O file variables                         }
-    FOutFile    : TStream;
-    FCrc32Val   : LongWord;       { CRC calculation variable                   }
-    FBufferSize : LongWord;
-    FOnPercent  : Integer;
-    FOnProgress : TProgressEvent;
-    Procedure UpdC32(Octet: Byte);
-  Public
-    Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
-    Procedure Compress; Virtual; Abstract;
-    Class Function ZipID : Word; virtual; Abstract;
-    Property BufferSize : LongWord read FBufferSize;
-    Property OnPercent : Integer Read FOnPercent Write FOnPercent;
-    Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
-    Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
-  end;
-
-  { TDeCompressor }
-  TDeCompressor = Class(TObject)
-  Protected
-    FInFile     : TStream;        { I/O file variables                         }
-    FOutFile    : TStream;
-    FCrc32Val   : LongWord;       { CRC calculation variable                   }
-    FBufferSize : LongWord;
-    FOnPercent  : Integer;
-    FOnProgress : TProgressEvent;
-    Procedure UpdC32(Octet: Byte);
-  Public
-    Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
-    Procedure DeCompress; Virtual; Abstract;
-    Class Function ZipID : Word; virtual; Abstract;
-    Property BufferSize : LongWord read FBufferSize;
-    Property OnPercent : Integer Read FOnPercent Write FOnPercent;
-    Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
-    Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
-  end;
-
-  { TShrinker }
-
-Const
-   TABLESIZE   =   8191;
-   FIRSTENTRY  =    257;
-
-Type
-  CodeRec =  Packed Record
-    Child   : Smallint;
-    Sibling : Smallint;
-    Suffix  : Byte;
-  end;
-  CodeArray   =  Array[0..TABLESIZE] of CodeRec;
-  TablePtr    =  ^CodeArray;
-
-  FreeListPtr    =  ^FreeListArray;
-  FreeListArray  =  Array[FIRSTENTRY..TABLESIZE] of Word;
-
-  BufPtr      =  PByte;
-
-  TShrinker = Class(TCompressor)
-  Private
-    FBufSize    : LongWord;
-    MaxInBufIdx :  LongWord;      { Count of valid chars in input buffer       }
-    InputEof    :  Boolean;       { End of file indicator                      }
-    CodeTable   :  TablePtr;      { Points to code table for LZW compression   }
-    FreeList    :  FreeListPtr;   { Table of free code table entries           }
-    NextFree    :  Word;          { Index into free list table                 }
-
-    ClearList   :  Array[0..1023] of Byte;  { Bit mapped structure used in     }
-                                            {    during adaptive resets        }
-    CodeSize    :  Byte;     { Size of codes (in bits) currently being written }
-    MaxCode     :  Word;   { Largest code that can be written in CodeSize bits }
-    InBufIdx,                     { Points to next char in buffer to be read   }
-    OutBufIdx   :  LongWord;      { Points to next free space in output buffer }
-    InBuf,                        { I/O buffers                                }
-    OutBuf      :  BufPtr;
-    FirstCh     :  Boolean;  { Flag indicating the START of a shrink operation }
-    TableFull   :  Boolean;  { Flag indicating a full symbol table             }
-    SaveByte    :  Byte;     { Output code buffer                              }
-    BitsUsed    :  Byte;     { Index into output code buffer                   }
-    BytesIn     :  LongInt;  { Count of input file bytes processed             }
-    BytesOut    :  LongInt;  { Count of output bytes                           }
-    FOnBytes    : Longint;
-    Procedure FillInputBuffer;
-    Procedure WriteOutputBuffer;
-    Procedure FlushOutput;
-    Procedure PutChar(B : Byte);
-    procedure PutCode(Code : Smallint);
-    Procedure InitializeCodeTable;
-    Procedure Prune(Parent : Word);
-    Procedure Clear_Table;
-    Procedure Table_Add(Prefix : Word; Suffix : Byte);
-    function  Table_Lookup(TargetPrefix : Smallint;
-                           TargetSuffix : Byte;
-                           Out FoundAt  : Smallint) : Boolean;
-    Procedure Shrink(Suffix : Smallint);
-    Procedure ProcessLine(Const Source : String);
-    Procedure DoOnProgress(Const Pct : Double); Virtual;
-  Public
-    Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); override;
-    Destructor Destroy; override;
-    Procedure Compress; override;
-    Class Function ZipID : Word; override;
-  end;
-
-  { TDeflater }
-
-  TDeflater = Class(TCompressor)
-  private
-    FCompressionLevel: TCompressionlevel;
-  Public
-    Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
-    Procedure Compress; override;
-    Class Function ZipID : Word; override;
-    Property CompressionLevel : TCompressionlevel Read FCompressionLevel Write FCompressionLevel;
-  end;
-
-  { TInflater }
-
-  TInflater = Class(TDeCompressor)
-  Public
-    Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
-    Procedure DeCompress; override;
-    Class Function ZipID : Word; override;
-  end;
-
-  { TZipper }
-
-  TZipper = Class(TObject)
-  Private
-    FZipping    : Boolean;
-    FBufSize    : LongWord;
-    FFileName   :  String;         { Name of resulting Zip file                 }
-    FFiles      : TStrings;
-    FInMemSize  : Integer;
-    FOutFile    : TFileStream;
-    FInFile     : TFileStream;     { I/O file variables                         }
-    LocalHdr    : Local_File_Header_Type;
-    CentralHdr  : Central_File_Header_Type;
-    EndHdr      : End_of_Central_Dir_Type;
-    FOnPercent  : LongInt;
-    FOnProgress : TProgressEvent;
-    FOnEndOfFile : TOnEndOfFileEvent;
-    FOnStartFile : TOnStartFileEvent;
-  Protected
-    Procedure OpenOutput;
-    Procedure CloseOutput;
-    Procedure CloseInput;
-    Procedure StartZipFile(Item : TZipItem);
-    Function  UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
-    Procedure BuildZipDirectory;
-    Procedure DoEndOfFile;
-    Procedure ZipOneFile(Item : TZipItem); virtual;
-    Function  OpenInput(InFileName : String) : Boolean;
-    Procedure GetFileInfo;
-    Procedure SetBufSize(Value : LongWord);
-    Procedure SetFileName(Value : String);
-    Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
-  Public
-    Constructor Create;
-    Destructor Destroy;override;
-    Procedure ZipAllFiles; virtual;
-    Procedure ZipFiles(AFileName : String; FileList : TStrings);
-    Procedure Clear;
-  Public
-    Property BufferSize : LongWord Read FBufSize Write SetBufSize;
-    Property OnPercent : Integer Read FOnPercent Write FOnPercent;
-    Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
-    Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
-    Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
-    Property FileName : String Read FFileName Write SetFileName;
-    Property Files : TStrings Read FFiles;
-    Property InMemSize : Integer Read FInMemSize Write FInMemSize;
-  end;
-
-  { TYbZipper }
-
-  { TUnZipper }
-
-  TUnZipper = Class(TObject)
-  Private
-    FUnZipping  : Boolean;
-    FBufSize    : LongWord;
-    FFileName   :  String;         { Name of resulting Zip file                 }
-    FOutputPath : String;
-    FFiles      : TStrings;
-    FZipEntries : TFPObjectList;
-    FOutFile    : TFileStream;
-    FZipFile     : TFileStream;     { I/O file variables                         }
-    LocalHdr    : Local_File_Header_Type;
-    CentralHdr  : Central_File_Header_Type;
-    EndHdr      : End_of_Central_Dir_Type;
-
-    FOnPercent  : LongInt;
-    FOnProgress : TProgressEvent;
-    FOnEndOfFile : TOnEndOfFileEvent;
-    FOnStartFile : TOnStartFileEvent;
-  Protected
-    Procedure OpenInput;
-    Procedure CloseOutput;
-    Procedure CloseInput;
-    Procedure ReadZipHeader(Item : TZipItem; out ACRC : LongWord;out AMethod : Word);
-    Procedure ReadZipDirectory;
-    Procedure DoEndOfFile;
-    Procedure UnZipOneFile(Item : TZipItem); virtual;
-    Function  OpenOutput(OutFileName : String) : Boolean;
-    Procedure SetBufSize(Value : LongWord);
-    Procedure SetFileName(Value : String);
-    Procedure SetOutputPath(Value:String);
-    Function CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
-  Public
-    Constructor Create;
-    Destructor Destroy;override;
-    Procedure UnZipAllFiles; virtual;
-    Procedure UnZipFiles(AFileName : String; FileList : TStrings);
-    Procedure UnZipAllFiles(AFileName : String);
-    Procedure Clear;
-  Public
-    Property BufferSize : LongWord Read FBufSize Write SetBufSize;
-    Property OnPercent : Integer Read FOnPercent Write FOnPercent;
-    Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
-    Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
-    Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
-    Property FileName : String Read FFileName Write SetFileName;
-    Property OutputPath : String Read FOutputPath Write SetOutputPath;
-    Property Files : TStrings Read FFiles;
-  end;
-
-  EZipError = Class(Exception);
-
-Implementation
-
-ResourceString
-  SErrBufsizeChange = 'Changing buffer size is not allowed while (un)zipping';
-  SErrFileChange = 'Changing output file name is not allowed while (un)zipping';
-  SErrInvalidCRC = 'Invalid CRC checksum while unzipping %s';
-  SErrCorruptZIP = 'Corrupt ZIP file %s';
-  SErrUnsupportedCompressionFormat = 'Unsupported compression format %d';
-
-{ ---------------------------------------------------------------------
-    Auxiliary
-  ---------------------------------------------------------------------}
-
-Procedure DateTimeToZipDateTime(DT : TDateTime; out ZD,ZT : Word);
-
-Var
-  Y,M,D,H,N,S,MS : Word;
-
-begin
-  DecodeDate(DT,Y,M,D);
-  DecodeTime(DT,H,N,S,MS);
-  Y:=Y-1980;
-  ZD:=d+(32*M)+(512*Y);
-  ZT:=(S div 2)+(32*N)+(2048*h);
-end;
-
-Procedure ZipDateTimeToDateTime(ZD,ZT : Word;out DT : TDateTime);
-
-Var
-  Y,M,D,H,N,S,MS : Word;
-
-begin
-  MS:=0;
-  S:=(ZT and 31) shl 1;
-  N:=(ZT shr 5) and 63;
-  H:=(ZT shr 12) and 31;
-  D:=ZD and 31;
-  M:=(ZD shr 5) and 15;
-  Y:=((ZD shr 9) and 127)+1980;
-  DT:=ComposeDateTime(EncodeDate(Y,M,D),EncodeTime(H,N,S,MS));
-end;
-
-{ ---------------------------------------------------------------------
-    TDeCompressor
-  ---------------------------------------------------------------------}
-
-
-Procedure TDeCompressor.UpdC32(Octet: Byte);
-
-Begin
-  FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
-end;
-
-constructor TDeCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
-begin
-  FinFile:=AInFile;
-  FoutFile:=AOutFile;
-  FBufferSize:=ABufSize;
-  CRC32Val:=$FFFFFFFF;
-end;
-
-
-{ ---------------------------------------------------------------------
-    TCompressor
-  ---------------------------------------------------------------------}
-
-
-Procedure TCompressor.UpdC32(Octet: Byte);
-
-Begin
-  FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
-end;
-
-constructor TCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
-begin
-  FinFile:=AInFile;
-  FoutFile:=AOutFile;
-  FBufferSize:=ABufSize;
-  CRC32Val:=$FFFFFFFF;
-end;
-
-
-{ ---------------------------------------------------------------------
-    TDeflater
-  ---------------------------------------------------------------------}
-
-constructor TDeflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
-begin
-  Inherited;
-  FCompressionLevel:=clDefault;
-end;
-
-
-procedure TDeflater.Compress;
-
-Var
-  Buf : PByte;
-  I,Count,NewCount : Integer;
-  C : TCompressionStream;
-
-begin
-  CRC32Val:=$FFFFFFFF;
-  Buf:=GetMem(FBufferSize);
-  Try
-    C:=TCompressionStream.Create(FCompressionLevel,FOutFile,True);
-    Try
-      Repeat
-        Count:=FInFile.Read(Buf^,FBufferSize);
-        For I:=0 to Count-1 do
-          UpdC32(Buf[i]);
-        NewCount:=Count;
-        While (NewCount>0) do
-          NewCount:=NewCount-C.Write(Buf^,NewCount);
-      Until (Count=0);
-    Finally
-      C.Free;
-    end;
-  Finally
-    FreeMem(Buf);
-  end;
-  Crc32Val:=NOT Crc32Val;
-end;
-
-class function TDeflater.ZipID: Word;
-begin
-  Result:=8;
-end;
-
-{ ---------------------------------------------------------------------
-    TInflater
-  ---------------------------------------------------------------------}
-
-constructor TInflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
-begin
-  Inherited;
-end;
-
-
-procedure TInflater.DeCompress;
-
-Var
-  Buf : PByte;
-  I,Count : Integer;
-  C : TDeCompressionStream;
-
-begin
-  CRC32Val:=$FFFFFFFF;
-  Buf:=GetMem(FBufferSize);
-  Try
-    C:=TDeCompressionStream.Create(FInFile,True);
-    Try
-      Repeat
-        Count:=C.Read(Buf^,FBufferSize);
-        For I:=0 to Count-1 do
-          UpdC32(Buf[i]);
-        FOutFile.Write(Buf^,Count);
-      Until (Count=0);
-    Finally
-      C.Free;
-    end;
-  Finally
-    FreeMem(Buf);
-  end;
-  Crc32Val:=NOT Crc32Val;
-end;
-
-class function TInflater.ZipID: Word;
-begin
-  Result:=8;
-end;
-
-
-{ ---------------------------------------------------------------------
-    TShrinker
-  ---------------------------------------------------------------------}
-
-Const
-   DefaultInMemSize = 256*1024; { Files larger than 256k are processed on disk   }
-   DefaultBufSize =  16384;     { Use 16K file buffers                             }
-   MINBITS     =      9;        { Starting code size of 9 bits                     }
-   MAXBITS     =     13;        { Maximum code size of 13 bits                     }
-   SPECIAL     =    256;        { Special function code                            }
-   INCSIZE     =      1;        { Code indicating a jump in code size              }
-   CLEARCODE   =      2;        { Code indicating code table has been cleared      }
-   STDATTR     =    $23;        { Standard file attribute for DOS Find First/Next  }
-
-constructor TShrinker.Create(AInFile, AOutFile : TStream; ABufSize : LongWord);
-begin
-  Inherited;
-  FBufSize:=ABufSize;
-  InBuf:=GetMem(FBUFSIZE);
-  OutBuf:=GetMem(FBUFSIZE);
-  CodeTable:=GetMem(SizeOf(CodeTable^));
-  FreeList:=GetMem(SizeOf(FreeList^));
-end;
-
-destructor TShrinker.Destroy;
-begin
-  FreeMem(CodeTable);
-  FreeMem(FreeList);
-  FreeMem(InBuf);
-  FreeMem(OutBuf);
-  inherited Destroy;
-end;
-
-Procedure TShrinker.Compress;
-
-Var
-   OneString : String;
-   Remaining : Word;
-
-begin
-  BytesIn := 1;
-  BytesOut := 1;
-  InitializeCodeTable;
-  FillInputBuffer;
-  FirstCh:= TRUE;
-  Crc32Val:=$FFFFFFFF;
-  FOnBytes:=Round((FInFile.Size * FOnPercent) / 100);
-  While NOT InputEof do
-    begin
-    Remaining:=Succ(MaxInBufIdx - InBufIdx);
-    If Remaining>255 then
-      Remaining:=255;
-    If Remaining=0 then
-      FillInputBuffer
-    else
-      begin
-      SetLength(OneString,Remaining);
-      Move(InBuf[InBufIdx], OneString[1], Remaining);
-      Inc(InBufIdx, Remaining);
-      ProcessLine(OneString);
-      end;
-    end;
-   Crc32Val := NOT Crc32Val;
-   ProcessLine('');
-end;
-
-class function TShrinker.ZipID: Word;
-begin
-  Result:=1;
-end;
-
-
-Procedure TShrinker.DoOnProgress(Const Pct: Double);
-
-begin
-  If Assigned(FOnProgress) then
-    FOnProgress(Self,Pct);
-end;
-
-
-Procedure TShrinker.FillInputBuffer;
-
-Begin
-   MaxInbufIDx:=FInfile.Read(InBuf[0], FBufSize);
-   If MaxInbufIDx=0 then
-      InputEof := TRUE
-   else
-      InputEOF := FALSE;
-   InBufIdx := 0;
-end;
-
-
-Procedure TShrinker.WriteOutputBuffer;
-Begin
-  FOutFile.WriteBuffer(OutBuf[0], OutBufIdx);
-  OutBufIdx := 0;
-end;
-
-
-Procedure TShrinker.PutChar(B : Byte);
-
-Begin
-  OutBuf[OutBufIdx] := B;
-  Inc(OutBufIdx);
-  If OutBufIdx>=FBufSize then
-    WriteOutputBuffer;
-  Inc(BytesOut);
-end;
-
-Procedure TShrinker.FlushOutput;
-Begin
-  If OutBufIdx>0 then
-    WriteOutputBuffer;
-End;
-
-
-procedure TShrinker.PutCode(Code : Smallint);
-
-var
-  ACode : LongInt;
-  XSize : Smallint;
-
-begin
-  if (Code=-1) then
-    begin
-    if BitsUsed>0 then
-      PutChar(SaveByte);
-    end
-  else
-    begin
-    ACode := Longint(Code);
-    XSize := CodeSize+BitsUsed;
-    ACode := (ACode shl BitsUsed) or SaveByte;
-    while (XSize div 8) > 0 do
-      begin
-      PutChar(Lo(ACode));
-      ACode := ACode shr 8;
-      Dec(XSize,8);
-      end;
-    BitsUsed := XSize;
-    SaveByte := Lo(ACode);
-    end;
-end;
-
-
-Procedure TShrinker.InitializeCodeTable;
-
-Var
-   I  :  Word;
-Begin
-   For I := 0 to TableSize do
-     begin
-     With CodeTable^[I] do
-       begin
-       Child := -1;
-       Sibling := -1;
-       If (I<=255) then
-         Suffix := I;
-       end;
-     If (I>=257) then
-       FreeList^[I] := I;
-     end;
-   NextFree  := FIRSTENTRY;
-   TableFull := FALSE;
-end;
-
-
-Procedure TShrinker.Prune(Parent : Word);
-
-Var
-   CurrChild   : Smallint;
-   NextSibling : Smallint;
-Begin
-  CurrChild := CodeTable^[Parent].Child;
-  { Find first Child that has descendants .. clear any that don't }
-  While (CurrChild <> -1) AND (CodeTable^[CurrChild].Child = -1) do
-    begin
-    CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
-    CodeTable^[CurrChild].Sibling := -1;
-     { Turn on ClearList bit to indicate a cleared entry }
-    ClearList[CurrChild DIV 8] := (ClearList[CurrChild DIV 8] OR (1 SHL (CurrChild MOD 8)));
-    CurrChild := CodeTable^[Parent].Child;
-    end;
-  If CurrChild <> -1 then
-    begin   { If there are any children left ...}
-    Prune(CurrChild);
-    NextSibling := CodeTable^[CurrChild].Sibling;
-    While NextSibling <> -1 do
-      begin
-      If CodeTable^[NextSibling].Child = -1 then
-        begin
-        CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
-        CodeTable^[NextSibling].Sibling := -1;
-        { Turn on ClearList bit to indicate a cleared entry }
-        ClearList[NextSibling DIV 8] := (ClearList[NextSibling DIV 8] OR (1 SHL (NextSibling MOD 8)));
-        NextSibling := CodeTable^[CurrChild].Sibling;
-        end
-      else
-        begin
-        CurrChild := NextSibling;
-        Prune(CurrChild);
-        NextSibling := CodeTable^[CurrChild].Sibling;
-        end;
-      end;
-    end;
-end;
-
-
-Procedure TShrinker.Clear_Table;
-Var
-   Node : Word;
-Begin
-   FillChar(ClearList, SizeOf(ClearList), $00);
-   For Node := 0 to 255 do
-     Prune(Node);
-   NextFree := Succ(TABLESIZE);
-   For Node := TABLESIZE downto FIRSTENTRY do
-     begin
-     If (ClearList[Node DIV 8] AND (1 SHL (Node MOD 8))) <> 0 then
-       begin
-       Dec(NextFree);
-       FreeList^[NextFree] := Node;
-       end;
-     end;
-   If NextFree <= TABLESIZE then
-     TableFull := FALSE;
-end;
-
-
-Procedure TShrinker.Table_Add(Prefix : Word; Suffix : Byte);
-Var
-   FreeNode : Word;
-Begin
-  If NextFree <= TABLESIZE then
-    begin
-    FreeNode := FreeList^[NextFree];
-    Inc(NextFree);
-    CodeTable^[FreeNode].Child := -1;
-    CodeTable^[FreeNode].Sibling := -1;
-    CodeTable^[FreeNode].Suffix := Suffix;
-    If CodeTable^[Prefix].Child  = -1 then
-      CodeTable^[Prefix].Child := FreeNode
-    else
-      begin
-      Prefix := CodeTable^[Prefix].Child;
-      While CodeTable^[Prefix].Sibling <> -1 do
-        Prefix := CodeTable^[Prefix].Sibling;
-      CodeTable^[Prefix].Sibling := FreeNode;
-      end;
-    end;
-  if NextFree > TABLESIZE then
-    TableFull := TRUE;
-end;
-
-function TShrinker.Table_Lookup(    TargetPrefix : Smallint;
-                          TargetSuffix : Byte;
-                      Out FoundAt      : Smallint   ) : Boolean;
-
-var TempPrefix : Smallint;
-
-begin
-  TempPrefix := TargetPrefix;
-  Table_lookup := False;
-  if CodeTable^[TempPrefix].Child <> -1 then
-    begin
-    TempPrefix := CodeTable^[TempPrefix].Child;
-    repeat
-      if CodeTable^[TempPrefix].Suffix = TargetSuffix then
-        begin
-        Table_lookup := True;
-        break;
-        end;
-      if CodeTable^[TempPrefix].Sibling = -1 then
-        break;
-      TempPrefix := CodeTable^[TempPrefix].Sibling;
-    until False;
-  end;
-  if Table_Lookup then
-    FoundAt := TempPrefix
-  else
-    FoundAt := -1;
-end;
-
-Procedure TShrinker.Shrink(Suffix : Smallint);
-
-Const
-  LastCode : Smallint = 0;
-
-Var
-  WhereFound : Smallint;
-
-Begin
-  If FirstCh then
-    begin
-    SaveByte := $00;
-    BitsUsed := 0;
-    CodeSize := MINBITS;
-    MaxCode  := (1 SHL CodeSize) - 1;
-    LastCode := Suffix;
-    FirstCh  := FALSE;
-    end
-  else
-    begin
-    If Suffix <> -1 then
-      begin
-      If TableFull then
-        begin
-        Putcode(LastCode);
-        PutCode(SPECIAL);
-        Putcode(CLEARCODE);
-        Clear_Table;
-        Table_Add(LastCode, Suffix);
-        LastCode := Suffix;
-        end
-      else
-        begin
-        If Table_Lookup(LastCode, Suffix, WhereFound) then
-          begin
-          LastCode  := WhereFound;
-          end
-        else
-          begin
-          PutCode(LastCode);
-          Table_Add(LastCode, Suffix);
-          LastCode := Suffix;
-          If (FreeList^[NextFree] > MaxCode) and (CodeSize < MaxBits) then
-            begin
-            PutCode(SPECIAL);
-            PutCode(INCSIZE);
-            Inc(CodeSize);
-            MaxCode := (1 SHL CodeSize) -1;
-            end;
-          end;
-        end;
-      end
-    else
-      begin
-      PutCode(LastCode);
-      PutCode(-1);
-      FlushOutput;
-      end;
-    end;
-end;
-
-Procedure TShrinker.ProcessLine(Const Source : String);
-
-Var
-  I : Word;
-
-Begin
-  If Source = '' then
-    Shrink(-1)
-  else
-    For I := 1 to Length(Source) do
-      begin
-      Inc(BytesIn);
-      If (Pred(BytesIn) MOD FOnBytes) = 0 then
-        DoOnProgress(100 * ( BytesIn / FInFile.Size));
-      UpdC32(Ord(Source[I]));
-      Shrink(Ord(Source[I]));
-      end;
-end;
-
-{ ---------------------------------------------------------------------
-    TZipper
-  ---------------------------------------------------------------------}
-
-
-Procedure TZipper.GetFileInfo;
-
-Var
-   Info : TSearchRec;
-   I       : Longint;
-   NewNode : TZipItem;
-
-
-Begin
-   For I := 0 to FFiles.Count-1 do
-    begin
-     If FindFirst(FFiles[I], STDATTR, Info)=0 then
-       try
-         NewNode:=TZipItem.Create;
-         NewNode.Path := ExtractFilePath(FFiles[i]);
-         NewNode.Name := Info.Name;
-         NewNode.Size := Info.Size;
-         NewNode.DateTime:=FileDateToDateTime(Info.Time);
-         FFiles.Objects[i]:=NewNode;
-       finally
-         FindClose(Info);
-       end;
-     end;  
-end;
-
-Procedure TZipper.OpenOutput;
-
-Begin
-  FOutFile:=TFileStream.Create(FFileName,fmCreate);
-End;
-
-
-Function TZipper.OpenInput(InFileName : String) : Boolean;
-
-Begin
-  FInFile:=TFileStream.Create(InFileName,fmOpenRead);
-  Result:=True;
-  If Assigned(FOnStartFile) then
-    FOnStartFile(Self,InFileName);
-End;
-
-
-Procedure TZipper.CloseOutput;
-
-Begin
-  FreeAndNil(FOutFile);
-end;
-
-
-Procedure TZipper.CloseInput;
-
-Begin
-  FreeAndNil(FInFile);
-end;
-
-
-Procedure TZipper.StartZipFile(Item : TZipItem);
-
-Begin
-  FillChar(LocalHdr,SizeOf(LocalHdr),0);
-  With LocalHdr do
-    begin
-    Signature := LOCAL_FILE_HEADER_SIGNATURE;
-    Extract_Version_Reqd := 10;
-    Bit_Flag := 0;
-    Compress_Method := 1;
-    DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
-    Crc32 := 0;
-    Compressed_Size := 0;
-    Uncompressed_Size := Item.Size;
-    FileName_Length := 0;
-    Extra_Field_Length := 0;
-  end ;
-End;
-
-
-Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
-var
-  ZFileName  : ShortString;
-Begin
-  ZFileName:=Item.Path+Item.Name;
-  With LocalHdr do
-    begin
-    FileName_Length := Length(ZFileName);
-    Compressed_Size := FZip.Size;
-    Crc32 := ACRC;
-    Compress_method:=AMethod;
-    Result:=Not (Compressed_Size >= Uncompressed_Size);
-    If Not Result then
-      begin                     { No...                          }
-      Compress_Method := 0;                  { ...change stowage type      }
-      Compressed_Size := Uncompressed_Size;  { ...update compressed size   }
-      end;
-    end;
-  FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
-  FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
-End;
-
-
-Procedure TZipper.BuildZipDirectory;
-
-Var
-   SavePos   : LongInt;
-   HdrPos    : LongInt;
-   CenDirPos : LongInt;
-   Entries   : Word;
-   ZFileName  : ShortString;
-
-Begin
-   Entries := 0;
-   CenDirPos := FOutFile.Position;
-   FOutFile.Seek(0,soFrombeginning);             { Rewind output file }
-   HdrPos := FOutFile.Position;
-   FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
-   Repeat
-     SetLength(ZFileName,LocalHdr.FileName_Length);
-     FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
-     SavePos := FOutFile.Position;
-     FillChar(CentralHdr,SizeOf(CentralHdr),0);
-     With CentralHdr do
-       begin
-       Signature := CENTRAL_FILE_HEADER_SIGNATURE;
-       MadeBy_Version := LocalHdr.Extract_Version_Reqd;
-       Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
-       Last_Mod_Time:=localHdr.Last_Mod_Time;
-       Last_Mod_Date:=localHdr.Last_Mod_Date;
-       File_Comment_Length := 0;
-       Starting_Disk_Num := 0;
-       Internal_Attributes := 0;
-       External_Attributes := faARCHIVE;
-       Local_Header_Offset := HdrPos;
-       end;
-     FOutFile.Seek(0,soFromEnd);
-     FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
-     FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
-     Inc(Entries);
-     FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
-     HdrPos:=FOutFile.Position;
-     FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
-   Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
-   FOutFile.Seek(0,soFromEnd);
-   FillChar(EndHdr,SizeOf(EndHdr),0);
-   With EndHdr do
-     begin
-     Signature := END_OF_CENTRAL_DIR_SIGNATURE;
-     Disk_Number := 0;
-     Central_Dir_Start_Disk := 0;
-     Entries_This_Disk := Entries;
-     Total_Entries := Entries;
-     Central_Dir_Size := FOutFile.Size-CenDirPos;
-     Start_Disk_Offset := CenDirPos;
-     ZipFile_Comment_Length := 0;
-     FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
-     end;
-end;
-
-Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
-
-begin
-  Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
-end;
-
-Procedure TZipper.ZipOneFile(Item : TZipItem);
-
-Var
-  CRC : LongWord;
-  ZMethod : Word;
-  ZipStream : TStream;
-  TmpFileName : String;
-
-Begin
-  OpenInput(Item.Path+Item.Name);
-  Try
-    StartZipFile(Item);
-    If (FInfile.Size<=FInMemSize) then
-      ZipStream:=TMemoryStream.Create
-    else
-      begin
-      TmpFileName:=ChangeFileExt(FFileName,'.tmp');
-      ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
-      end;
-    Try
-      With CreateCompressor(Item, FinFile,ZipStream) do
-        Try
-          OnProgress:=Self.OnProgress;
-          OnPercent:=Self.OnPercent;
-          Compress;
-          CRC:=Crc32Val;
-          ZMethod:=ZipID;
-        Finally
-          Free;
-        end;
-      If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
-        // Compressed file smaller than original file.
-        FOutFile.CopyFrom(ZipStream,0)
-      else
-        begin
-        // Original file smaller than compressed file.
-        FInfile.Seek(0,soFromBeginning);
-        FOutFile.CopyFrom(FInFile,0);
-        end;
-    finally
-      ZipStream.Free;
-      If (TmpFileName<>'') then
-        DeleteFile(TmpFileName);
-    end;
-  Finally
-    CloseInput;
-  end;
-end;
-
-Procedure TZipper.ZipAllFiles;
-Var
-   Item : TZipItem;
-   I : Integer;
-   filecnt : integer;
-Begin
-  if FFiles.Count=0 then
-    exit;
-  FZipping:=True;
-  Try
-    GetFileInfo;
-    OpenOutput;
-    Try
-      filecnt:=0;
-      For I:=0 to FFiles.Count-1 do
-        begin
-          Item:=FFiles.Objects[i] as TZipItem;
-	  if assigned(Item) then
-	    begin
-              ZipOneFile(Item);
-	      inc(filecnt);
-	    end;  
-        end;
-      if filecnt>0 then	
-        BuildZipDirectory;
-    finally
-      CloseOutput;
-    end;
-  finally
-    FZipping:=False;
-  end;
-end;
-
-
-Procedure TZipper.SetBufSize(Value : LongWord);
-
-begin
-  If FZipping then
-    Raise EZipError.Create(SErrBufsizeChange);
-  If Value>=DefaultBufSize then
-    FBufSize:=Value;
-end;
-
-Procedure TZipper.SetFileName(Value : String);
-
-begin
-  If FZipping then
-    Raise EZipError.Create(SErrFileChange);
-  FFileName:=Value;
-end;
-
-Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
-
-begin
-  FFiles.Assign(FileList);
-  FFileName:=AFileName;
-  ZipAllFiles;
-end;
-
-Procedure TZipper.DoEndOfFile;
-
-Var
-  ComprPct : Double;
-
-begin
-  If (LocalHdr.Uncompressed_Size>0) then
-    ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
-  else
-    ComprPct := 0;
-  If Assigned(FOnEndOfFile) then
-    FOnEndOfFile(Self,ComprPct);
-end;
-
-Constructor TZipper.Create;
-
-begin
-  FBufSize:=DefaultBufSize;
-  FInMemSize:=DefaultInMemSize;
-  FFiles:=TStringList.Create;
-  TStringlist(FFiles).Sorted:=True;
-  FOnPercent:=1;
-end;
-
-Procedure TZipper.Clear;
-
-Var
-  I : Integer;
-
-begin
-  For I:=0 to FFiles.Count-1 do
-    FFiles.Objects[i].Free;
-  FFiles.Clear;
-end;
-
-Destructor TZipper.Destroy;
-
-begin
-  Clear;
-  FreeAndNil(FFiles);
-  Inherited;
-end;
-
-
-{ ---------------------------------------------------------------------
-    TUnZipper
-  ---------------------------------------------------------------------}
-
-Procedure TUnZipper.OpenInput;
-
-Begin
-  FZipFile:=TFileStream.Create(FFileName,fmOpenRead);
-End;
-
-
-Function TUnZipper.OpenOutput(OutFileName : String) : Boolean;
-
-Begin
-  FOutFile:=TFileStream.Create(OutFileName,fmCreate);
-  Result:=True;
-  If Assigned(FOnStartFile) then
-    FOnStartFile(Self,OutFileName);
-End;
-
-
-Procedure TUnZipper.CloseOutput;
-
-Begin
-  FreeAndNil(FOutFile);
-end;
-
-
-Procedure TUnZipper.CloseInput;
-
-Begin
-  FreeAndNil(FZipFile);
-end;
-
-
-Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
-
-Begin
-  FZipFile.Seek(Item.HdrPos,soFromBeginning);
-  FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
-  With LocalHdr do
-    begin
-      SetLength(Item.Name,Filename_Length);
-      FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
-      FZipFile.Seek(Extra_Field_Length,soCurrent);
-      Item.Size:=Uncompressed_Size;
-      ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
-      ACrc:=Crc32;
-      AMethod:=Compress_method;
-    end;
-End;
-
-
-Procedure TUnZipper.ReadZipDirectory;
-
-Var
-   i,
-   EndHdrPos,
-   CenDirPos : LongInt;
-   NewNode   : TZipItem;
-Begin
-   EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
-   if EndHdrPos < 0 then
-     raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-   FZipFile.Seek(EndHdrPos,soFromBeginning);
-   FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
-   With EndHdr do
-     begin
-       if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
-         raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-       CenDirPos:=Start_Disk_Offset;
-     end;
-   FZipFile.Seek(CenDirPos,soFrombeginning);
-   for i:=0 to EndHdr.Entries_This_Disk-1 do
-     begin
-       FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
-       With CentralHdr do
-         begin
-           if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
-             raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-           NewNode:=TZipItem.Create;
-           NewNode.HdrPos := Local_Header_Offset;
-           SetLength(NewNode.Name,Filename_Length);
-           FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
-           FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
-           FZipEntries.Add(NewNode);
-         end;
-     end;
-end;
-
-Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
-var
-  Count : Int64;
-begin
-  case AMethod of
-    8 :
-      Result:=TInflater.Create(AZipFile,AOutFile,FBufSize);
-  else
-    raise EZipError.CreateFmt(SErrUnsupportedCompressionFormat,[AMethod]);
-  end;
-end;
-
-Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
-
-Var
-  Count : Longint;
-  CRC : LongWord;
-  ZMethod : Word;
-  OutputFileName : string;
-Begin
-  Try
-    ReadZipHeader(Item,CRC,ZMethod);
-    OutputFileName:=Item.Name;
-    if FOutputPath<>'' then
-      OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
-    OpenOutput(OutputFileName);  
-    if ZMethod=0 then
-      begin
-        Count:=FOutFile.CopyFrom(FZipFile,LocalHdr.Compressed_Size);
-{$warning TODO: Implement CRC Check}
-      end
-    else
-      With CreateDecompressor(Item, ZMethod, FZipFile, FOutFile) do
-        Try
-          OnProgress:=Self.OnProgress;
-          OnPercent:=Self.OnPercent;
-          DeCompress;
-          if CRC<>Crc32Val then
-            raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
-        Finally
-          Free;
-        end;
-  Finally
-    CloseOutput;
-  end;
-end;
-
-
-Procedure TUnZipper.UnZipAllFiles;
-Var
-   Item : TZipItem;
-   I : Integer;
-
-Begin
-  FUnZipping:=True;
-  Try
-    OpenInput;
-    Try
-      ReadZipDirectory;
-      For I:=0 to FZipEntries.Count-1 do
-        begin
-          Item:=FZipEntries[i] as TZipItem;
-	  if (FFiles=nil) or
-	     (FFiles.IndexOf(Item.Name)<>-1) then
-            UnZipOneFile(Item);
-        end;
-    Finally
-       CloseInput;
-    end;
-  finally
-    FUnZipping:=False;
-  end;
-end;
-
-
-Procedure TUnZipper.SetBufSize(Value : LongWord);
-
-begin
-  If FUnZipping then
-    Raise EZipError.Create(SErrBufsizeChange);
-  If Value>=DefaultBufSize then
-    FBufSize:=Value;
-end;
-
-Procedure TUnZipper.SetFileName(Value : String);
-
-begin
-  If FUnZipping then
-    Raise EZipError.Create(SErrFileChange);
-  FFileName:=Value;
-end;
-
-Procedure TUnZipper.SetOutputPath(Value:String);
-begin
-  If FUnZipping then
-    Raise EZipError.Create(SErrFileChange);
-  FOutputPath:=Value;
-end;
-
-Procedure TUnZipper.UnZipFiles(AFileName : String; FileList : TStrings);
-
-begin
-  FFiles.Assign(FileList);
-  FFileName:=AFileName;
-  UnZipAllFiles;
-end;
-
-Procedure TUnZipper.UnZipAllFiles(AFileName : String);
-
-begin
-  FFileName:=AFileName;
-  UnZipAllFiles;
-end;
-
-Procedure TUnZipper.DoEndOfFile;
-
-Var
-  ComprPct : Double;
-
-begin
-  If (LocalHdr.Uncompressed_Size>0) then
-    ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
-  else
-    ComprPct := 0;
-  If Assigned(FOnEndOfFile) then
-    FOnEndOfFile(Self,ComprPct);
-end;
-
-Constructor TUnZipper.Create;
-
-begin
-  FBufSize:=DefaultBufSize;
-  FFiles:=TStringList.Create;
-  FZipEntries:=TFPObjectList.Create(true);
-  TStringlist(FFiles).Sorted:=True;
-  FOnPercent:=1;
-end;
-
-Procedure TUnZipper.Clear;
-
-Var
-  I : Integer;
-
-begin
-  For I:=0 to FFiles.Count-1 do
-    FFiles.Objects[i].Free;
-  FFiles.Clear;
-  FZipEntries.Clear;
-end;
-
-Destructor TUnZipper.Destroy;
-
-begin
-  Clear;
-  FreeAndNil(FFiles);
-  FreeAndNil(FZipEntries);
-  Inherited;
-end;
-
-End.

+ 0 - 440
utils/fppkg/fcl20/zstream.pp

@@ -1,440 +0,0 @@
-{
-    This file is part of the Free Pascal run time library.
-    Copyright (c) 1999-2000 by the Free Pascal development team
-
-    Implementation of compression streams.
-
-    See the file COPYING.FPC, included in this distribution,
-    for details about the copyright.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- **********************************************************************}
-{$mode objfpc}
-
-unit zstream;
-
-
-{ ---------------------------------------------------------------------
-  For linux and freebsd it's also possible to use ZLib instead
-  of paszlib. You need to undefine 'usepaszlib'.
-  ---------------------------------------------------------------------}
-
-{$define usepaszlib}
-
-
-interface
-
-uses
-  Sysutils, Classes
-{$ifdef usepaszlib}
-  ,paszlib,zbase
-{$else}
-  ,zlib
-{$endif}
-  ;
-
-{$H+}
-
-type
-  // Error reporting.
-  EZlibError = class(EStreamError);
-  ECompressionError = class(EZlibError);
-  EDecompressionError = class(EZlibError);
-
-  TCustomZlibStream = class(TOwnerStream)
-  private
-    FStrmPos: Integer;
-    FOnProgress: TNotifyEvent;
-    FZRec: TZStream;
-    FBuffer: array [Word] of Byte;
-  protected
-    procedure Progress(Sender: TObject); dynamic;
-    property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
-  public
-    constructor Create(Strm: TStream);
-  end;
-
-  TCompressionLevel = (clNone, clFastest, clDefault, clMax);
-
-  TCompressionStream = class(TCustomZlibStream)
-  private
-    function GetCompressionRate: extended;
-    function CompressionCheck(code: Integer): Integer;
-    procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
-                          var OutBuf: Pointer; var OutBytes: Integer);
-  public
-    constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream; ASkipHeader : Boolean = False);
-    destructor Destroy; override;
-    function Read(var Buffer; Count: Longint): Longint; override;
-    function Write(const Buffer; Count: Longint): Longint; override;
-    function Seek(Offset: Longint; Origin: Word): Longint; override;
-    property CompressionRate: extended read GetCompressionRate;
-    property OnProgress;
-  end;
-
-  TDecompressionStream = class(TCustomZlibStream)
-  private
-    function DecompressionCheck(code: Integer): Integer;
-    procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
-    OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
-  public
-    constructor Create(ASource: TStream; ASkipHeader : Boolean = False);
-    destructor Destroy; override;
-    function Read(var Buffer; Count: Longint): Longint; override;
-    function Write(const Buffer; Count: Longint): Longint; override;
-    function Seek(Offset: Longint; Origin: Word): Longint; override;
-    property OnProgress;
-  end;
-
-  TGZOpenMode = (gzOpenRead,gzOpenWrite);
-
-  TGZFileStream = Class(TStream)
-    Private
-    FOpenMode : TGZOpenmode;
-    FFIle : gzfile;
-    Public
-    Constructor Create(FileName: String;FileMode: TGZOpenMode);
-    Destructor Destroy;override;
-    Function Read(Var Buffer; Count : longint): longint;override;
-    function Write(const Buffer; Count: Longint): Longint; override;
-    function Seek(Offset: Longint; Origin: Word): Longint; override;
-    end;
-
-
-implementation
-
-Const
-  ErrorStrings : array [0..6] of string =
-    ('Unknown error %d','Z_ERRNO','Z_STREAM_ERROR',
-     'Z_DATA_ERROR','Z_MEM_ERROR','Z_BUF_ERROR','Z_VERSION_ERROR');
-  SCouldntOpenFile = 'Couldn''t open file : %s';
-  SReadOnlyStream = 'Decompression streams are read-only';
-  SWriteOnlyStream = 'Compression streams are write-only';
-  SSeekError = 'Compression stream seek error';
-  SInvalidSeek = 'Invalid Compression seek operation';
-
-procedure TCompressionStream.CompressBuf(const InBuf: Pointer; InBytes: Integer;
-                      var OutBuf: Pointer; var OutBytes: Integer);
-var
-  strm: TZStream;
-  P: Pointer;
-begin
-  FillChar(strm, sizeof(strm), 0);
-  OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
-  OutBuf:=GetMem(OutBytes);
-  try
-    strm.next_in := InBuf;
-    strm.avail_in := InBytes;
-    strm.next_out := OutBuf;
-    strm.avail_out := OutBytes;
-    CompressionCheck(deflateInit(strm, Z_BEST_COMPRESSION));
-    try
-      while CompressionCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
-      begin
-        P := OutBuf;
-        Inc(OutBytes, 256);
-        ReallocMem(OutBuf,OutBytes);
-        strm.next_out := PByte(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
-        strm.avail_out := 256;
-      end;
-    finally
-      CompressionCheck(deflateEnd(strm));
-    end;
-    ReallocMem(OutBuf,strm.total_out);
-    OutBytes := strm.total_out;
-  except
-    FreeMem(OutBuf);
-    raise;
-  end;
-end;
-
-
-procedure TDecompressionStream.DecompressBuf(const InBuf: Pointer; InBytes: Integer;
-       OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
-var
-  strm: TZStream;
-  P: Pointer;
-  BufInc: Integer;
-Type
-  PByte = ^Byte;
-begin
-  FillChar(strm, sizeof(strm), 0);
-  BufInc := (InBytes + 255) and not 255;
-  if OutEstimate = 0 then
-    OutBytes := BufInc
-  else
-    OutBytes := OutEstimate;
-  OutBuf:=GetMem(OutBytes);
-  try
-    strm.next_in := InBuf;
-    strm.avail_in := InBytes;
-    strm.next_out := OutBuf;
-    strm.avail_out := OutBytes;
-    DecompressionCheck(inflateInit(strm));
-    try
-      while DecompressionCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do
-      begin
-        P := OutBuf;
-        Inc(OutBytes, BufInc);
-        ReallocMem(OutBuf, OutBytes);
-        strm.next_out := PByte(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
-        strm.avail_out := BufInc;
-      end;
-    finally
-      DecompressionCheck(inflateEnd(strm));
-    end;
-    ReallocMem(OutBuf, strm.total_out);
-    OutBytes := strm.total_out;
-  except
-    FreeMem(OutBuf);
-    raise;
-  end;
-end;
-
-
-// TCustomZlibStream
-
-constructor TCustomZLibStream.Create(Strm: TStream);
-begin
-  inherited Create(Strm);
-  FStrmPos := Strm.Position;
-end;
-
-procedure TCustomZLibStream.Progress(Sender: TObject);
-begin
-  if Assigned(FOnProgress) then FOnProgress(Sender);
-end;
-
-
-// TCompressionStream
-
-constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
-  Dest: TStream; ASkipHeader : Boolean = False);
-const
-  Levels: array [TCompressionLevel] of ShortInt =
-    (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
-begin
-  inherited Create(Dest);
-  FZRec.next_out := @FBuffer[0];
-  FZRec.avail_out := sizeof(FBuffer);
-  If ASkipHeader then
-    CompressionCheck(deflateInit2(FZRec, Levels[CompressionLevel],Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0))
-  else
-    CompressionCheck(deflateInit(FZRec, Levels[CompressionLevel]));
-end;
-
-destructor TCompressionStream.Destroy;
-begin
-  FZRec.next_in := nil;
-  FZRec.avail_in := 0;
-  try
-    if Source.Position <> FStrmPos then Source.Position := FStrmPos;
-    while (CompressionCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
-      and (FZRec.avail_out = 0) do
-    begin
-      Source.WriteBuffer(FBuffer, sizeof(FBuffer));
-      FZRec.next_out := @FBuffer[0];
-      FZRec.avail_out := sizeof(FBuffer);
-    end;
-    if FZRec.avail_out < sizeof(FBuffer) then
-      Source.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
-  finally
-    deflateEnd(FZRec);
-  end;
-  inherited Destroy;
-end;
-
-function TCompressionStream.CompressionCheck(code: Integer): Integer;
-begin
-  Result := code;
-  if (code < 0) then
-    if code < -6 then
-      raise ECompressionError.CreateFmt(Errorstrings[0],[Code])
-    else
-      raise ECompressionError.Create(ErrorStrings[Abs(Code)]);
-end;
-
-
-function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
-begin
-  raise ECompressionError.Create('Invalid stream operation');
-  result:=0;
-end;
-
-function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
-begin
-  FZRec.next_in := @Buffer;
-  FZRec.avail_in := Count;
-  if Source.Position <> FStrmPos then Source.Position := FStrmPos;
-  while (FZRec.avail_in > 0) do
-  begin
-    CompressionCheck(deflate(FZRec, 0));
-    if FZRec.avail_out = 0 then
-    begin
-      Source.WriteBuffer(FBuffer, sizeof(FBuffer));
-      FZRec.next_out := @FBuffer[0];
-      FZRec.avail_out := sizeof(FBuffer);
-      FStrmPos := Source.Position;
-      Progress(Self);
-    end;
-  end;
-  Result := Count;
-end;
-
-function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
-begin
-  if (Offset = 0) and (Origin = soFromCurrent) then
-    Result := FZRec.total_in
-  else
-    raise ECompressionError.Create(SInvalidSeek);
-end;
-
-function TCompressionStream.GetCompressionRate: extended;
-begin
-  Result:=0.0;
-{  With FZrec do
-    if total_in = 0 then
-      GetCompressionRate:=0.0
-    else
-      GetCompressionRate:=1.0E2*(1.0E0-(total_out/total_in));
-}
-end;
-
-
-// TDecompressionStream
-
-constructor TDecompressionStream.Create(ASource: TStream; ASkipHeader : Boolean = False);
-begin
-  inherited Create(ASource);
-  FZRec.next_in := @FBuffer[0];
-  If ASkipHeader then
-    DeCompressionCheck(inflateInit2(FZRec,-MAX_WBITS))
-  else
-    DeCompressionCheck(inflateInit(FZRec));
-end;
-
-destructor TDecompressionStream.Destroy;
-begin
-  if FZRec.avail_in <> 0 then
-    Source.Seek(-FZRec.avail_in, soFromCurrent);
-  inflateEnd(FZRec);
-  inherited Destroy;
-end;
-
-function TDecompressionStream.DecompressionCheck(code: Integer): Integer;
-begin
-  Result := code;
-  If Code<0 then
-    if code < -6 then
-      raise EDecompressionError.CreateFmt(Errorstrings[0],[Code])
-    else
-      raise EDecompressionError.Create(ErrorStrings[Abs(Code)]);
-end;
-
-function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
-begin
-  FZRec.next_out := @Buffer;
-  FZRec.avail_out := Count;
-  if Source.Position <> FStrmPos then Source.Position := FStrmPos;
-  while (FZRec.avail_out > 0) do
-  begin
-    if FZRec.avail_in = 0 then
-    begin
-      FZRec.avail_in := Source.Read(FBuffer, sizeof(FBuffer));
-      if FZRec.avail_in = 0 then
-        begin
-          Result := Count - FZRec.avail_out;
-          Exit;
-        end;
-      FZRec.next_in := @FBuffer[0];
-      FStrmPos := Source.Position;
-      Progress(Self);
-    end;
-    if DeCompressionCheck(inflate(FZRec, 0)) = Z_STREAM_END then
-        begin
-          Result := Count - FZRec.avail_out;
-          Exit;
-        end;
-  end;
-  Result := Count;
-end;
-
-function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
-begin
-  raise EDecompressionError.Create('Invalid stream operation');
-  result:=0;
-end;
-
-function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
-var
-  I: Integer;
-  Buf: array [0..4095] of Char;
-begin
-  if (Offset = 0) and (Origin = soFromBeginning) then
-  begin
-    DecompressionCheck(inflateReset(FZRec));
-    FZRec.next_in := @FBuffer[0];
-    FZRec.avail_in := 0;
-    Source.Position := 0;
-    FStrmPos := 0;
-  end
-  else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
-          ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
-  begin
-    if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
-    if Offset > 0 then
-    begin
-      for I := 1 to Offset div sizeof(Buf) do
-        ReadBuffer(Buf, sizeof(Buf));
-      ReadBuffer(Buf, Offset mod sizeof(Buf));
-    end;
-  end
-  else
-    raise EDecompressionError.Create(SInvalidSeek);
-  Result := FZRec.total_out;
-end;
-
-// TGZFileStream
-
-Constructor TGZFileStream.Create(FileName: String;FileMode: TGZOpenMode);
-
-Const OpenStrings : array[TGZOpenMode] of pchar = ('rb','wb');
-
-begin
-   FOpenMode:=FileMode;
-   FFile:=gzopen (PChar(FileName),Openstrings[FileMode]);
-   If FFile=Nil then
-     Raise ezlibError.CreateFmt (SCouldntOpenFIle,[FileName]);
-end;
-
-Destructor TGZFileStream.Destroy;
-begin
-  gzclose(FFile);
-  Inherited Destroy;
-end;
-
-Function TGZFileStream.Read(Var Buffer; Count : longint): longint;
-begin
-  If FOpenMode=gzOpenWrite then
-    Raise ezliberror.create(SWriteOnlyStream);
-  Result:=gzRead(FFile,@Buffer,Count);
-end;
-
-function TGZFileStream.Write(const Buffer; Count: Longint): Longint;
-begin
-  If FOpenMode=gzOpenRead then
-    Raise EzlibError.Create(SReadonlyStream);
-  Result:=gzWrite(FFile,@Buffer,Count);
-end;
-
-function TGZFileStream.Seek(Offset: Longint; Origin: Word): Longint;
-begin
-  Result:=gzseek(FFile,Offset,Origin);
-  If Result=-1 then
-    Raise eZlibError.Create(SSeekError);
-end;
-
-end.

+ 58 - 0
utils/fppkg/fpmake.pp

@@ -0,0 +1,58 @@
+{$mode objfpc}{$H+}
+program fpmake;
+
+ { Generated automatically by fppkg on 5-2-07 }
+
+uses fpmkunit;
+
+Var
+  T : TTarget;
+
+begin
+  With Installer do 
+    begin
+    { 
+      fppkg
+    } 
+    StartPackage('fppkg');
+    Version:='2.0.0';
+    Options:='-Filnet/sys';
+    Dependencies.Add('fcl');
+    Dependencies.Add('libcurl');
+    T:=Targets.AddProgram('fppkg');
+    T.ResourceStrings:=True;
+      T.Directory:='';
+    T:=Targets.AddUnit('fpmktype');
+      T.Directory:='';
+    T:=Targets.AddUnit('fpmkunit');
+      T.Directory:='';
+    T:=Targets.AddUnit('fprepos');
+    T.ResourceStrings:=True;
+      T.Directory:='';
+    T:=Targets.AddUnit('fpxmlrep');
+    T.ResourceStrings:=True;
+      T.Directory:='';
+    T:=Targets.AddUnit('pkgropts');
+      T.Directory:='';
+    T:=Targets.AddUnit('pkghandler');
+      T.Directory:='';
+    T:=Targets.AddUnit('pkgmkconv');
+      T.Directory:='';
+    T:=Targets.AddUnit('pkgdownload');
+      T.Directory:='';
+    T:=Targets.AddUnit('pkgwget');
+    T.OS:=[linux,freebsd,netbsd,openbsd,darwin,solaris,win32,win64,wince];
+      T.Directory:='';
+    T:=Targets.AddUnit('pkglnet');
+    T.OS:=[linux,freebsd,netbsd,openbsd,darwin,solaris,win32,win64,wince];
+      T.Directory:='';
+    T:=Targets.AddUnit('pkglibcurl');
+    T.OS:=[linux,freebsd,netbsd,openbsd,darwin,solaris];
+      T.Directory:='';
+    T:=Targets.AddExampleunit('rep2xml');
+      T.Directory:='';
+    EndPackage;
+    Run;
+    end;
+end.
+

+ 5062 - 0
utils/fppkg/fpmkunitsrc.inc

@@ -0,0 +1,5062 @@
+{$ifdef Delphi}
+const fpmkunitsrc : array[0..549] of string[240]=(
+{$else Delphi}
+const fpmkunitsrc : array[0..549,1..240] of char=(
+{$endif Delphi}
+  '{'#010+
+  '    This file is part of the Free Pascal Makefile Package'#010+
+  #010+
+  '    Implementation of fpmake classes and functions'#010+
+  #010+
+  '    Copyright (c) 2007 by the freepascal team'#010+
+  #010+
+  '    See the file COPYING.FPC, included in this distribution,'#010+
+  '    for details abo','ut the copyright.'#010+
+  #010+
+  '    This program is distributed in the hope that it will be useful,'#010+
+  '    but WITHOUT ANY WARRANTY; without even the implied warranty of'#010+
+  '    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'#010+
+  #010+
+  ' ***************************','****************************************'+
+  '***}'#010+
+  #010+
+  'unit fpmkunit;'#010+
+  #010+
+  '{$Mode objfpc}'#010+
+  '{$H+}'#010+
+  '{$inline on}'#010+
+  #010+
+  'Interface'#010+
+  #010+
+  '{$ifndef NO_UNIT_PROCESS}'#010+
+  '  {$define HAS_UNIT_PROCESS}'#010+
+  '{$endif NO_UNIT_PROCESS}'#010+
+  #010+
+  '{$ifndef NO_UNIT_ZIPPER}'#010+
+  '  {$define HAS_UNIT_ZIPPER','}'#010+
+  '{$endif NO_UNIT_ZIPPER}'#010+
+  #010+
+  'uses'#010+
+  '  SysUtils, Classes, StrUtils'#010+
+  '{$ifdef HAS_UNIT_PROCESS}'#010+
+  '  ,process'#010+
+  '{$endif HAS_UNIT_PROCESS}'#010+
+  '{$ifdef HAS_UNIT_ZIPPER}'#010+
+  '  ,zipper'#010+
+  '{$endif HAS_UNIT_ZIPPER}'#010+
+  '  ;'#010+
+  #010+
+  'Type'#010+
+  '  TFileType = (ftSource,ftUnit,ftObject,ftRes','ource,ftExecutable,ftSt'+
+  'aticLibrary,'#010+
+  '               ftSharedLibrary);'#010+
+  '  TFileTypes = set of TFileType;'#010+
+  #010+
+  '  // Please keep this order, see OSCPUpossible below'#010+
+  '  TCpu=(cpuNone,'#010+
+  '    i386,m68k,powerpc,sparc,x86_64,arm,powerpc64'#010+
+  '  );'#010+
+  '  TCPUS = Set',' of TCPU;'#010+
+  #010+
+  '  // Please keep this order, see OSCPUpossible below'#010+
+  '  TOS=(osNone,'#010+
+  '    linux,go32v2,win32,os2,freebsd,beos,netbsd,'#010+
+  '    amiga,atari, solaris, qnx, netware, openbsd,wdosx,'#010+
+  '    palmos,macos,darwin,emx,watcom,morphos,netwlibc,'#010+
+  '    w','in64,wince,gba,nds,embedded,symbian'#010+
+  '  );'#010+
+  '  TOSes = Set of TOS;'#010+
+  #010+
+  '  TCompilerMode = (cmFPC,cmTP,cmObjFPC,cmDelphi,cmMacPas);'#010+
+  '  TCompilerModes = Set of TCompilerMode;'#010+
+  #010+
+  '  TTargetType = (ttProgram,ttUnit,ttImplicitUnit,ttCleanOnlyUnit,ttExa'+
+  'mpleU','nit,ttExampleProgram);'#010+
+  '  TTargetTypes = set of TTargetType;'#010+
+  #010+
+  '  TTargetState = (tsNeutral,tsNeedCompile,tsNoCompile,tsCompiled,tsIns'+
+  'talled,tsNotFound);'#010+
+  '  TTargetStates = Set of TTargetState;'#010+
+  #010+
+  '  TSourceType = (stDoc,stSrc,stExample,stTest);'#010+
+  ' ',' TSourceTypes = set of TSourceType;'#010+
+  #010+
+  '  TVerboseLevel = (vlError,vlWarning,vlInfo,vldebug);'#010+
+  '  TVerboseLevels = Set of TVerboseLevel;'#010+
+  #010+
+  '  TCommandAt = (caBeforeCompile,caAfterCompile,'#010+
+  '                caBeforeInstall,caAfterInstall,'#010+
+  '           ','     caBeforeArchive,caAfterArchive,'#010+
+  '                caBeforeClean,caAfterClean,'#010+
+  '                caBeforeDownload,caAfterDownload);'#010+
+  #010+
+  '  TDependencyType = (depPackage,depImplicitPackage,depUnit,depInclude)'+
+  ';'#010+
+  '  TDependencyTypes = set of TDepend','encyType;'#010+
+  #010+
+  '  TLogEvent = Procedure (Level : TVerboseLevel; Const Msg : String) of'+
+  ' Object;'#010+
+  #010+
+  '  TRunMode = (rmCompile,rmBuild,rmInstall,rmArchive,rmClean,rmManifest'+
+  ');'#010+
+  #010+
+  'Const'#010+
+  '  // Aliases'#010+
+  '  Amd64   = X86_64;'#010+
+  '  PPC = PowerPC;'#010+
+  '  PPC64 = PowerPC64',';'#010+
+  '  DOS = Go32v2;'#010+
+  '  MacOSX = Darwin;'#010+
+  #010+
+  '  AllOSes = [Low(TOS)..High(TOS)];'#010+
+  '  AllCPUs = [Low(TCPU)..High(TCPU)];'#010+
+  '  AllUnixOSes  = [Linux,FreeBSD,NetBSD,OpenBSD,Darwin,QNX,BeOS,Solaris'+
+  '];'#010+
+  '  AllWindowsOSes  = [Win32,Win64,WinCE];'#010+
+  #010+
+  '  { This table ','is kept OS,Cpu because it is easier to maintain (PFV)'+
+  ' }'#010+
+  '  OSCpupossible : array[TOS,TCpu] of boolean = ('#010+
+  '    { os          none   i386   m68k   ppc    sparc  x86_64 arm    ppc'+
+  '64}'#010+
+  '    { none  }   ( false, false, false, false, false, false, f','alse, f'+
+  'alse),'#010+
+  '    { linux }   ( false, true,  true,  true,  true,  true,  true,  tru'+
+  'e),'#010+
+  '    { go32v2 }  ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { win32 }   ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '  ','  { os2 }     ( false, true,  false, false, false, false, false, f'+
+  'alse),'#010+
+  '    { freebsd } ( false, true,  true,  false, false, true,  false, fal'+
+  'se),'#010+
+  '    { beos }    ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { netbsd }  (',' false, true,  true,  true,  true,  false, false, f'+
+  'alse),'#010+
+  '    { amiga }   ( false, false, true,  true,  false, false, false, fal'+
+  'se),'#010+
+  '    { atari }   ( false, false, true,  false, false, false, false, fal'+
+  'se),'#010+
+  '    { solaris } ( false, true,  ','false, false, true,  false, false, f'+
+  'alse),'#010+
+  '    { qnx }     ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { netware } ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { openbsd } ( false, true,  true,  false, f','alse, false, false, f'+
+  'alse),'#010+
+  '    { wdosx }   ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { palmos }  ( false, false, true,  false, false, false, true,  fal'+
+  'se),'#010+
+  '    { macos }   ( false, false, false, true,  false, false, fa','lse, f'+
+  'alse),'#010+
+  '    { darwin }  ( false, true,  false, true,  false, false, false, tru'+
+  'e),'#010+
+  '    { emx }     ( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { watcom }  ( false, true,  false, false, false ,false, false, fal'+
+  'se),'#010+
+  '   ',' { morphos } ( false, false, false, true,  false ,false, false, f'+
+  'alse),'#010+
+  '    { netwlibc }( false, true,  false, false, false, false, false, fal'+
+  'se),'#010+
+  '    { win64   } ( false, false, false, false, false, true,  false, fal'+
+  'se),'#010+
+  '    { wince    }( ','false, true,  false, false, false, false, true,  f'+
+  'alse),'#010+
+  '    { gba    }  ( false, false, false, false, false, false, true,  fal'+
+  'se),'#010+
+  '    { nds    }  ( false, false, false, false, false, false, true,  fal'+
+  'se),'#010+
+  '    { embedded }( false, true,  t','rue,  true,  true,  true,  true,  t'+
+  'rue),'#010+
+  '    { symbian } ( false, true,  false, false, false, false, true,  fal'+
+  'se)'#010+
+  '  );'#010+
+  #010+
+  '  // Useful'#010+
+  '  UnitExt = '#039'.ppu'#039';'#010+
+  '  PPUExt  = UnitExt;'#010+
+  '  PasExt  = '#039'.pas'#039';'#010+
+  '  PPExt   = '#039'.pp'#039';'#010+
+  '  IncExt  = '#039'.inc'#039';'#010+
+  '  ObjEx','t  = '#039'.o'#039';'#010+
+  '  RstExt  = '#039'.rst'#039';'#010+
+  '  LibExt  = '#039'.a'#039';'#010+
+  '  SharedLibExt = '#039'.so'#039';'#010+
+  '  DLLExt  = '#039'.dll'#039';'#010+
+  '  ExeExt  = '#039'.exe'#039';'#010+
+  '  ZipExt  = '#039'.zip'#039';'#010+
+  #010+
+  '  FPMakePPFile = '#039'fpmake.pp'#039';'#010+
+  '  ManifestFile = '#039'manifest.xml'#039';'#010+
+  '  UnitConfigFile = '#039'fpunits.conf'#039';'#010+
+  #010+
+  '  DirNo','tFound = '#039'<dirnotfound>'#039';'#010+
+  #010+
+  '  UnitTargets = [ttUnit,ttImplicitUnit,ttCleanOnlyUnit,ttExampleUnit];'+
+  #010+
+  '  ProgramTargets = [ttProgram,ttExampleProgram];'#010+
+  #010+
+  '  DefaultMessages = [vlError,vlWarning];'#010+
+  '  AllMessages = [vlError,vlWarning,vlInfo];'#010+
+  #010+
+  #010+
+  'Type'#010,
+  '  { TNamedItem }'#010+
+  #010+
+  '  TNamedItem = Class(TCollectionItem)'#010+
+  '  private'#010+
+  '    FName: String;'#010+
+  '    procedure SetName(const AValue: String);virtual;'#010+
+  '  Public'#010+
+  '    property Name : String Read FName Write SetName;'#010+
+  '  end;'#010+
+  #010+
+  '  { TNamedCollection }'#010+
+  #010+
+  '  TNamed','Collection = Class(TCollection)'#010+
+  '  private'#010+
+  '    FUniqueNames: Boolean;'#010+
+  '  Public'#010+
+  '    Function IndexOfName(const AName : String) : Integer;'#010+
+  '    Function ItemByName(const AName : String) : TNamedItem;'#010+
+  '    Property UniqueNames : Boolean Read FUni','queNames;'#010+
+  '  end;'#010+
+  #010+
+  '  { TNamedItemList }'#010+
+  #010+
+  '  TNamedItemList = Class(TFPList)'#010+
+  '  private'#010+
+  '    function GetNamedItem(Index : Integer): TNamedItem;'#010+
+  '    procedure SetNamedItem(Index : Integer; const AValue: TNamedItem);'+
+  #010+
+  '  public'#010+
+  '    Function IndexOf','Name(const AName : String) : Integer;'#010+
+  '    Function ItemByName(const ANAme : String) : TNamedItem;'#010+
+  '    Property NamedItems[Index : Integer] : TNamedItem Read GetNamedIte'+
+  'm Write SetNamedItem; default;'#010+
+  '  end;'#010+
+  #010+
+  '  { TCommand }'#010+
+  '  TCommand = Class','(TNamedItem)'#010+
+  '  private'#010+
+  '    FAfterCommand: TNotifyEvent;'#010+
+  '    FBeforeCommand: TNotifyEvent;'#010+
+  '    FCommand: String;'#010+
+  '    FCommandAt: TCommandAt;'#010+
+  '    FDestFile: String;'#010+
+  '    FIgnoreResult: Boolean;'#010+
+  '    FOptions: String;'#010+
+  '    FSourceFile: String;'#010+
+  '  ','Public'#010+
+  '    Property SourceFile : String Read FSourceFile Write FSourceFile;'#010+
+  '    Property DestFile : String Read FDestFile Write FDestFile;'#010+
+  '    Property Command : String Read FCommand Write FCommand;'#010+
+  '    Property Options : String Read FOptio','ns Write FOptions;'#010+
+  '    Property At : TCommandAt Read FCommandAt Write FCommandAt;'#010+
+  '    Property IgnoreResult : Boolean Read FIgnoreResult Write FIgnoreRe'+
+  'sult;'#010+
+  '    Property BeforeCommand : TNotifyEvent Read FBeforeCommand Write FB'+
+  'eforeCommand',';'#010+
+  '    Property AfterCommand : TNotifyEvent Read FAfterCommand Write FAft'+
+  'erCommand;'#010+
+  '  end;'#010+
+  #010+
+  '  { TCommands }'#010+
+  #010+
+  '  TCommands = Class(TNamedCollection)'#010+
+  '  private'#010+
+  '    FDefaultAt: TCommandAt;'#010+
+  '    function GetCommand(const Dest : String): TCommand;'#010,
+  '    function GetCommandItem(Index : Integer): TCommand;'#010+
+  '    procedure SetCommandItem(Index : Integer; const AValue: TCommand);'+
+  #010+
+  '  Public'#010+
+  '    Function AddCommand(Const Cmd : String) : TCommand;'#010+
+  '    Function AddCommand(Const Cmd,Options : Stri','ng) : TCommand;'#010+
+  '    Function AddCommand(Const Cmd,Options,Dest,Source : String) : TCom'+
+  'mand;'#010+
+  '    Function AddCommand(At : TCommandAt; Const Cmd : String) : TComman'+
+  'd;'#010+
+  '    Function AddCommand(At : TCommandAt; Const Cmd,Options : String) :'+
+  ' TCom','mand;'#010+
+  '    Function AddCommand(At : TCommandAt; Const Cmd,Options, Dest,Sourc'+
+  'e : String) : TCommand;'#010+
+  '    Property CommandItems[Index : Integer] : TCommand Read GetCommandI'+
+  'tem Write SetCommandItem;'#010+
+  '    Property Commands[Dest : String] : TComm','and Read GetCommand; def'+
+  'ault;'#010+
+  '    Property DefaultAt : TCommandAt Read FDefaultAt Write FDefaultAt;'#010+
+  '  end;'#010+
+  #010+
+  '  { TConditionalString }'#010+
+  '  TConditionalString = Class'#010+
+  '  private'#010+
+  '    FOSes   : TOSes;'#010+
+  '    FCPUs   : TCPUs;'#010+
+  '    FValue  : String;'#010+
+  '  Pu','blic'#010+
+  '    Property Value : String Read FValue Write FValue;'#010+
+  '    Property OSes  : TOSes Read FOSes Write FOSes;'#010+
+  '    Property CPUs : TCPUs Read FCPUS Write FCPUs;'#010+
+  '  end;'#010+
+  #010+
+  '  { TConditionalStrings }'#010+
+  #010+
+  '  TConditionalStrings = Class(TFPList)'#010+
+  '  priv','ate'#010+
+  '    FCSClass : TClass;'#010+
+  '    function GetConditionalString(Index : Integer): TConditionalString'+
+  ';'#010+
+  '    procedure SetConditionalString(Index : Integer; const AValue: TCon'+
+  'ditionalString);'#010+
+  '  Public'#010+
+  '    Constructor Create(AClass:TClass);'#010+
+  '    Fu','nction Add(Const Value : String) : TConditionalString;inline;'#010+
+  '    Function Add(Const Value : String;const OSes:TOSes) : TConditional'+
+  'String;inline;'#010+
+  '    Function Add(Const Value : String;const CPUs:TCPUs) : TConditional'+
+  'String;inline;'#010+
+  '    Func','tion Add(Const Value : String;const CPUs:TCPUs;const OSes:TO'+
+  'Ses) : TConditionalString;'#010+
+  '    Property ConditionalStrings[Index : Integer] : TConditionalString '+
+  'Read GetConditionalString Write SetConditionalString; default;'#010+
+  '  end;'#010+
+  #010+
+  '  { TDepende','ncy }'#010+
+  '  TDependency = Class(TConditionalString)'#010+
+  '  private'#010+
+  '    // Package, Unit'#010+
+  '    FTarget : TObject;'#010+
+  '    // Includes and implicit/external packages'#010+
+  '    FDirectory,'#010+
+  '    FFullFileName : String;'#010+
+  '    FDependencyType : TDependencyType;'#010+
+  '  Public',#010+
+  '    Property Target : TObject Read FTarget Write FTarget;'#010+
+  '    Property DependencyType : TDependencyType Read FDependencyType;'#010+
+  '    Property Directory: String Read FDirectory;'#010+
+  '    Property FullFileName: String Read FFullFileName;'#010+
+  '  end;'#010+
+  #010+
+  '  T','Dependencies = Class(TConditionalStrings)'#010+
+  '    function GetDependency(Index : Integer): TDependency;'#010+
+  '    procedure SetDependency(Index : Integer; const AValue: TDependency'+
+  ');'#010+
+  '  Public'#010+
+  '    Function Add(Const Value : String) : TDependency;inlin','e;'#010+
+  '    Function Add(Const Value : String;const OSes:TOSes) : TDependency;'+
+  'inline;'#010+
+  '    Function Add(Const Value : String;const CPUs:TCPUs) : TDependency;'+
+  'inline;'#010+
+  '    Function Add(Const Value : String;const CPUs:TCPUs;const OSes:TOSe'+
+  's) : TDepen','dency;'#010+
+  '    Function AddUnit(Const Value : String) : TDependency;inline;'#010+
+  '    Function AddUnit(Const Value : String;const OSes:TOSes) : TDepende'+
+  'ncy;inline;'#010+
+  '    Function AddUnit(Const Value : String;const CPUs:TCPUs) : TDepende'+
+  'ncy;inline;'#010+
+  '    ','Function AddUnit(Const Value : String;const CPUs:TCPUs;const OSe'+
+  's:TOSes) : TDependency;'#010+
+  '    Function AddInclude(Const Value : String) : TDependency;inline;'#010+
+  '    Function AddInclude(Const Value : String;const OSes:TOSes) : TDepe'+
+  'ndency;inline;',#010+
+  '    Function AddInclude(Const Value : String;const CPUs:TCPUs) : TDepe'+
+  'ndency;inline;'#010+
+  '    Function AddInclude(Const Value : String;const CPUs:TCPUs;const OS'+
+  'es:TOSes) : TDependency;'#010+
+  '    Property Dependencies[Index : Integer] : TDependency Re','ad GetDep'+
+  'endency Write SetDependency; default;'#010+
+  '  end;'#010+
+  #010+
+  '  { TTarget }'#010+
+  #010+
+  '  TTarget = Class(TNamedItem)'#010+
+  '  private'#010+
+  '    FInstall : Boolean;'#010+
+  '    FAfterClean: TNotifyEvent;'#010+
+  '    FAfterCompile: TNotifyEvent;'#010+
+  '    FBeforeClean: TNotifyEvent;'#010+
+  '    FBefor','eCompile: TNotifyEvent;'#010+
+  '    FCPUs: TCPUs;'#010+
+  '    FOSes: TOSes;'#010+
+  '    FMode: TCompilerMode;'#010+
+  '    FResourceStrings: Boolean;'#010+
+  '    FObjectPath,'#010+
+  '    FUnitPath,'#010+
+  '    FIncludePath : TConditionalStrings;'#010+
+  '    FDependencies : TDependencies;'#010+
+  '    FCommands : ','TCommands;'#010+
+  '    FDirectory: String;'#010+
+  '    FExtension: String;'#010+
+  '    FFullSourceFileName : String;'#010+
+  '    FFileType: TFileType;'#010+
+  '    FOptions: String;'#010+
+  '    FFPCTarget: String;'#010+
+  '    FTargetState: TTargetState;'#010+
+  '    FTargetType: TTargetType;'#010+
+  '  Protected'#010+
+  ' ','   Function GetSourceFileName : String; virtual;'#010+
+  '    Function GetUnitFileName : String; virtual;'#010+
+  '    Function GetObjectFileName : String; virtual;'#010+
+  '    Function GetRSTFileName : String; Virtual;'#010+
+  '    Function GetProgramFileName(AOS : TOS) : S','tring; Virtual;'#010+
+  '  Public'#010+
+  '    Constructor Create(ACollection : TCollection); override;'#010+
+  '    Destructor Destroy; override;'#010+
+  '    Function GetOutputFileName (AOs : TOS) : String; Virtual;'#010+
+  '    procedure SetName(const AValue: String);override;'#010+
+  '    ','Procedure GetCleanFiles(List : TStrings; const APrefixU, APrefix'+
+  'B : String; ACPU:TCPU; AOS : TOS); virtual;'#010+
+  '    Procedure GetInstallFiles(List : TStrings; const APrefixU, APrefix'+
+  'B: String; ACPU:TCPU; AOS : TOS); virtual;'#010+
+  '    Procedure GetAr','chiveFiles(List : TStrings; ACPU:TCPU; AOS : TOS)'+
+  '; virtual;'#010+
+  '    Property Dependencies : TDependencies Read FDependencies;'#010+
+  '    Property Commands : TCommands Read FCommands;'#010+
+  '    Property State : TTargetState Read FTargetState;'#010+
+  '    Property Ta','rgetType : TTargetType Read FTargetType Write FTarget'+
+  'Type;'#010+
+  '    Property OSes : TOSes Read FOSes Write FOSes;'#010+
+  '    Property CPUs : TCPUs Read FCPUs Write FCPUs;'#010+
+  '    Property Mode : TCompilerMode Read FMode Write FMode;'#010+
+  '    Property Options : ','String Read FOptions Write Foptions;'#010+
+  '    Property SourceFileName: String Read GetSourceFileName ;'#010+
+  '    Property UnitFileName : String Read GetUnitFileName;'#010+
+  '    Property ObjectFileName : String Read GetObjectFileName;'#010+
+  '    Property RSTFileName',' : String Read GetRSTFileName;'#010+
+  '    Property FPCTarget : String Read FFPCTarget Write FFPCTarget;'#010+
+  '    Property Extension : String Read FExtension Write FExtension;'#010+
+  '    Property FileType : TFileType Read FFileType Write FFileType;'#010+
+  '    Propert','y Directory : String Read FDirectory Write FDirectory;'#010+
+  '    Property ResourceStrings : Boolean Read FResourceStrings Write FRe'+
+  'sourceStrings;'#010+
+  '    Property Install : Boolean Read FInstall Write FInstall;'#010+
+  '    Property FullSourceFileName: String',' Read FFullSourceFileName;'#010+
+  '    Property ObjectPath : TConditionalStrings Read FObjectPath;'#010+
+  '    Property UnitPath : TConditionalStrings Read FUnitPath;'#010+
+  '    Property IncludePath : TConditionalStrings Read FIncludePath;'#010+
+  '    // Events.'#010+
+  '    Prop','erty BeforeCompile : TNotifyEvent Read FBeforeCompile Write '+
+  'FBeforeCompile;'#010+
+  '    Property AfterCompile : TNotifyEvent Read FAfterCompile Write FAft'+
+  'erCompile;'#010+
+  '    Property BeforeClean : TNotifyEvent Read FBeforeClean Write FBefor'+
+  'eClean;'#010+
+  '    P','roperty AfterClean : TNotifyEvent Read FAfterClean Write FAfter'+
+  'Clean;'#010+
+  '  end;'#010+
+  #010+
+  '  { TTargets }'#010+
+  #010+
+  '  TTargets = Class(TNamedCollection)'#010+
+  '  private'#010+
+  '    function GetTargetItem(Index : Integer): TTarget;'#010+
+  '    function GetTarget(const AName : String):',' TTarget;'#010+
+  '    procedure SetTargetItem(Index : Integer; const AValue: TTarget);'#010+
+  '  Public'#010+
+  '    Function AddUnit(Const AUnitName : String) : TTarget;inline;'#010+
+  '    Function AddUnit(Const AUnitName : String;const OSes:TOSes) : TTar'+
+  'get;inline;'#010+
+  '    F','unction AddUnit(Const AUnitName : String;const CPUs:TCPUs) : TT'+
+  'arget;inline;'#010+
+  '    Function AddUnit(Const AUnitName : String;const CPUs:TCPUs;const O'+
+  'Ses:TOSes) : TTarget;'#010+
+  '    Function AddImplicitUnit(Const AUnitName : String;InstallUnit:bool'+
+  'e','an=true) : TTarget;inline;'#010+
+  '    Function AddImplicitUnit(Const AUnitName : String;const OSes:TOSes'+
+  ';InstallUnit:boolean=true) : TTarget;inline;'#010+
+  '    Function AddImplicitUnit(Const AUnitName : String;const CPUs:TCPUs'+
+  ';InstallUnit:boolean=true) :',' TTarget;inline;'#010+
+  '    Function AddImplicitUnit(Const AUnitName : String;const CPUs:TCPUs'+
+  ';const OSes:TOSes;InstallUnit:boolean=true) : TTarget;'#010+
+  '    Function AddProgram(Const AProgramName : String) : TTarget;inline;'+
+  #010+
+  '    Function AddProgram(Con','st AProgramName : String;const OSes:TOSes'+
+  ') : TTarget;inline;'#010+
+  '    Function AddProgram(Const AProgramName : String;const CPUs:TCPUs) '+
+  ': TTarget;inline;'#010+
+  '    Function AddProgram(Const AProgramName : String;const CPUs:TCPUs;c'+
+  'onst OSes:TOSes) : TT','arget;'#010+
+  '    Function AddExampleUnit(Const AUnitName : String) : TTarget;inline'+
+  ';'#010+
+  '    Function AddExampleUnit(Const AUnitName : String;const OSes:TOSes)'+
+  ' : TTarget;inline;'#010+
+  '    Function AddExampleUnit(Const AUnitName : String;const CPUs:TCPUs)'+
+  ' :',' TTarget;inline;'#010+
+  '    Function AddExampleUnit(Const AUnitName : String;const CPUs:TCPUs;'+
+  'const OSes:TOSes) : TTarget;'#010+
+  '    Function AddExampleProgram(Const AProgramName : String) : TTarget;'+
+  'inline;'#010+
+  '    Function AddExampleProgram(Const AProgramN','ame : String;const OSe'+
+  's:TOSes) : TTarget;inline;'#010+
+  '    Function AddExampleProgram(Const AProgramName : String;const CPUs:'+
+  'TCPUs) : TTarget;inline;'#010+
+  '    Function AddExampleProgram(Const AProgramName : String;const CPUs:'+
+  'TCPUs;const OSes:TOSes) : ','TTarget;'#010+
+  '    Property Targets[AName : String] : TTarget Read GetTarget; default'+
+  ';'#010+
+  '    Property TargetItems[Index : Integer] : TTarget Read GetTargetItem'+
+  ' Write SetTargetItem;'#010+
+  '  end;'#010+
+  #010+
+  '  { TSource }'#010+
+  #010+
+  '  TSource = Class(TNamedItem)'#010+
+  '  private'#010+
+  '    ','FSourceType : TSourceType;'#010+
+  '  Public'#010+
+  '    Constructor Create(ACollection : TCollection); override;'#010+
+  '    Destructor Destroy; override;'#010+
+  '    property SourceType : TSourceType read FSourceType;'#010+
+  '  end;'#010+
+  #010+
+  '  { TSources }'#010+
+  #010+
+  '  TSources = Class(TNamedColl','ection)'#010+
+  '  private'#010+
+  '    function GetSourceItem(Index : Integer): TSource;'#010+
+  '    procedure SetSourceItem(Index : Integer; const AValue: TSource);'#010+
+  '  public'#010+
+  '    Function AddDoc(const AFiles : String) : TSource;'#010+
+  '    Function AddSrc(const AFiles : S','tring) : TSource;'#010+
+  '    Function AddExample(const AFiles : String) : TSource;'#010+
+  '    Function AddTest(const AFiles : String) : TSource;'#010+
+  '    procedure AddDocFiles(const AFileMask: string; Recursive: boolean '+
+  '= False);'#010+
+  '    procedure AddSrcFiles(con','st AFileMask: string; Recursive: boolea'+
+  'n = False);'#010+
+  '    procedure AddExampleFiles(const AFileMask: string; Recursive: bool'+
+  'ean = False);'#010+
+  '    procedure AddTestFiles(const AFileMask: string; Recursive: boolean'+
+  ' = False);'#010+
+  '    Property SourceItems','[Index : Integer] : TSource Read GetSourceIt'+
+  'em Write SetSourceItem;default;'#010+
+  '  end;'#010+
+  #010+
+  '  { TPackage }'#010+
+  #010+
+  '  TPackage = Class(TNamedItem)'#010+
+  '  private'#010+
+  '    FAfterArchive: TNotifyEvent;'#010+
+  '    FAfterClean: TNotifyEvent;'#010+
+  '    FAfterCompile: TNotifyEvent;'#010+
+  '  ','  FAfterInstall: TNotifyEvent;'#010+
+  '    FAfterManifest: TNotifyEvent;'#010+
+  '    FBeforeArchive: TNotifyEvent;'#010+
+  '    FBeforeClean: TNotifyEvent;'#010+
+  '    FBeforeCompile: TNotifyEvent;'#010+
+  '    FBeforeInstall: TNotifyEvent;'#010+
+  '    FBeforeManifest: TNotifyEvent;'#010+
+  '    FU','nitPath,'#010+
+  '    FObjectPath,'#010+
+  '    FIncludePath,'#010+
+  '    FSourcePath,'#010+
+  '    FExamplePath,'#010+
+  '    FTestPath,'#010+
+  '    FCleanFiles,'#010+
+  '    FArchiveFiles,'#010+
+  '    FInstallFiles : TConditionalStrings;'#010+
+  '    FDependencies : TDependencies;'#010+
+  '    FCPUs: TCPUs;'#010+
+  '    FOSes: TOSes',';'#010+
+  '    FTargetState: TTargetState;'#010+
+  '    FTargets: TTargets;'#010+
+  '    FSources: TSources;'#010+
+  '    FDirectory: String;'#010+
+  '    FOptions: String;'#010+
+  '    FFileName: String;'#010+
+  '    FAuthor: String;'#010+
+  '    FLicense: String;'#010+
+  '    FExternalURL: String;'#010+
+  '    FVersion: String',';'#010+
+  '    FEmail : String;'#010+
+  '    FNeedLibC : Boolean;'#010+
+  '    FCommands : TCommands;'#010+
+  '    FDescriptionFile : String;'#010+
+  '    FDescription : String;'#010+
+  '    // Cached directory of installed packages'#010+
+  '    FUnitDir : String;'#010+
+  '    Function GetDescription : string;'#010,
+  '    Function GetFileName : string;'#010+
+  '  Protected'#010+
+  '    procedure SetName(const AValue: String);override;'#010+
+  '    procedure LoadUnitConfigFromFile(Const AFileName: String);'#010+
+  '    procedure SaveUnitConfigToFile(Const AFileName: String;ACPU:TCPU;A'+
+  'OS:TOS',');'#010+
+  '    procedure SaveUnitConfigToStream(S : TStream;ACPU:TCPU;AOS:TOS);'#010+
+  '    procedure LoadUnitConfigFromStream(S: TStream);'#010+
+  '  Public'#010+
+  '    constructor Create(ACollection: TCollection); override;'#010+
+  '    destructor destroy; override;'#010+
+  '    Procedure',' GetCleanFiles(List : TStrings; Const APrefixU, APrefix'+
+  'B : String; ACPU:TCPU; AOS : TOS); virtual;'#010+
+  '    procedure GetInstallFiles(List: TStrings;Types : TTargetTypes;Cons'+
+  't APrefix, APrefixU, APrefixB: String; ACPU:TCPU; AOS : TOS);'#010+
+  '    Proce','dure GetArchiveFiles(List : TStrings; ACPU:TCPU; AOS : TOS)'+
+  '; virtual;'#010+
+  '    Procedure GetManifest(Manifest : TStrings);'#010+
+  '    Property Version : String Read FVersion Write FVersion;'#010+
+  '    Property FileName : String Read GetFileName Write FFileNam','e;'#010+
+  '    Property ExternalURL : String Read FExternalURL Write FExternalURL'+
+  ';'#010+
+  '    Property Email : String Read FEmail Write FEmail;'#010+
+  '    Property Author : String Read FAuthor Write FAuthor;'#010+
+  '    Property License : String Read FLicense Write FLic','ense;'#010+
+  '    Property Directory : String Read FDirectory Write FDirectory;'#010+
+  '    Property Description : String Read GetDescription Write FDescripti'+
+  'on;'#010+
+  '    Property DescriptionFile : String Read FDescriptionFile Write FDes'+
+  'criptionFile;'#010+
+  '    // Com','piler options.'#010+
+  '    Property OSes : TOSes Read FOSes Write FOSes;'#010+
+  '    Property CPUs : TCPUs Read FCPUs Write FCPUs;'#010+
+  '    Property NeedLibC : Boolean Read FNeedLibC Write FNeedLibC;'#010+
+  '    Property Options: String Read FOptions Write FOptions;'#010+
+  '  ','  Property UnitPath : TConditionalStrings Read FUnitPath;'#010+
+  '    Property ObjectPath : TConditionalStrings Read FObjectPath;'#010+
+  '    Property IncludePath : TConditionalStrings Read FIncludePath;'#010+
+  '    Property SourcePath : TConditionalStrings Read F','SourcePath;'#010+
+  '    Property ExamplePath : TConditionalStrings Read FExamplePath;'#010+
+  '    Property TestPath : TConditionalStrings Read FTestPath;'#010+
+  '    // Targets and dependencies'#010+
+  '    Property InstallFiles : TConditionalStrings Read FInstallFiles;'#010+
+  '  ','  Property CleanFiles : TConditionalStrings Read FCleanFiles;'#010+
+  '    Property ArchiveFiles : TConditionalStrings Read FArchiveFiles;'#010+
+  '    Property Dependencies : TDependencies Read FDependencies;'#010+
+  '    Property Commands : TCommands Read FCommands',';'#010+
+  '    Property State : TTargetState Read FTargetState;'#010+
+  '    Property Targets : TTargets Read FTargets;'#010+
+  '    Property Sources : TSources Read FSources;'#010+
+  '    Property UnitDir : String Read FUnitDir Write FUnitDir;'#010+
+  '    // events'#010+
+  '    Property Befo','reCompile : TNotifyEvent Read FBeforeCompile Write '+
+  'FBeforeCompile;'#010+
+  '    Property AfterCompile : TNotifyEvent Read FAfterCompile Write FAft'+
+  'erCompile;'#010+
+  '    Property BeforeInstall : TNotifyEvent Read FBeforeInstall Write FB'+
+  'eforeInstall;'#010+
+  '    Prop','erty AfterInstall : TNotifyEvent Read FAfterInstall Write FA'+
+  'fterInstall;'#010+
+  '    Property BeforeClean : TNotifyEvent Read FBeforeClean Write FBefor'+
+  'eClean;'#010+
+  '    Property AfterClean : TNotifyEvent Read FAfterClean Write FAfterCl'+
+  'ean;'#010+
+  '    Property B','eforeArchive : TNotifyEvent Read FBeforeArchive Write '+
+  'FBeforeArchive;'#010+
+  '    Property AfterArchive : TNotifyEvent Read FAfterArchive Write FAft'+
+  'erArchive;'#010+
+  '    Property BeforeManifest : TNotifyEvent Read FBeforeManifest Write '+
+  'FBeforeManifest;'#010+
+  '  ','  Property AfterManifest : TNotifyEvent Read FAfterManifest Write '+
+  'FAfterManifest;'#010+
+  '  end;'#010+
+  #010+
+  '  { TPackages }'#010+
+  #010+
+  '  TPackages = Class(TNamedCollection)'#010+
+  '  private'#010+
+  '    function GetPackage(const AName : String): TPackage;'#010+
+  '    function GetPackageItem(','AIndex : Integer): TPackage;'#010+
+  '    procedure SetPackageItem(AIndex : Integer; const AValue: TPackage)'+
+  ';'#010+
+  '  Public'#010+
+  '    Function AddPackage(Const AName : String) : TPackage;'#010+
+  '    Property Packages[AName : String] : TPackage Read GetPackage ; Def'+
+  'au','lt;'#010+
+  '    Property PackageItems[AIndex : Integer] : TPackage Read GetPackage'+
+  'Item Write SetPackageItem;'#010+
+  '  end;'#010+
+  #010+
+  '  { TCustomDefaults }'#010+
+  #010+
+  '  TCustomDefaults = Class(TPersistent)'#010+
+  '  Private'#010+
+  '    FArchive: String;'#010+
+  '    FCompiler: String;'#010+
+  '    FCopy: Str','ing;'#010+
+  '    FMkDir: String;'#010+
+  '    FMove: String;'#010+
+  '    FOptions: String;'#010+
+  '    FCPU: TCPU;'#010+
+  '    FOS: TOS;'#010+
+  '    FMode : TCompilerMode;'#010+
+  '    FCompilerVersion : String;'#010+
+  '    FPrefix: String;'#010+
+  '    FLocalUnitDir,'#010+
+  '    FGlobalUnitDir,'#010+
+  '    FBaseInstallDir,'#010+
+  '    F','UnitInstallDir,'#010+
+  '    FBinInstallDir,'#010+
+  '    FDocInstallDir,'#010+
+  '    FExamplesInstallDir : String;'#010+
+  '    FRemove: String;'#010+
+  '    FTarget: String;'#010+
+  '    FUnixPaths: Boolean;'#010+
+  '    FNoFPCCfg: Boolean;'#010+
+  '    FSourceExt : String;'#010+
+  '    function GetLocalUnitDir: Stri','ng;'#010+
+  '    function GetGlobalUnitDir: String;'#010+
+  '    function GetBaseInstallDir: String;'#010+
+  '    function GetBinInstallDir: String;'#010+
+  '    function GetCompiler: String;'#010+
+  '    function GetDocInstallDir: String;'#010+
+  '    function GetExamplesInstallDir: String;'#010+
+  ' ','   function GetUnitInstallDir: String;'#010+
+  '    procedure SetLocalUnitDir(const AValue: String);'#010+
+  '    procedure SetGlobalUnitDir(const AValue: String);'#010+
+  '    procedure SetBaseInstallDir(const AValue: String);'#010+
+  '    procedure SetCPU(const AValue: TCPU',');'#010+
+  '    procedure SetOS(const AValue: TOS);'#010+
+  '    procedure SetPrefix(const AValue: String);'#010+
+  '    procedure SetTarget(const AValue: String);'#010+
+  '  Protected'#010+
+  '    procedure RecalcTarget;'#010+
+  '  Public'#010+
+  '    Constructor Create;'#010+
+  '    Procedure InitDefaults;'#010+
+  '  ','  Procedure Assign(ASource : TPersistent);override;'#010+
+  '    procedure CompilerDefaults; virtual;'#010+
+  '    Procedure LocalInit(Const AFileName : String);'#010+
+  '    Procedure LoadFromFile(Const AFileName : String);'#010+
+  '    Procedure SaveToFile(Const AFileName :',' String);'#010+
+  '    procedure SaveToStream(S : TStream);virtual;'#010+
+  '    procedure LoadFromStream(S : TStream);virtual;'#010+
+  '    // Compile Information'#010+
+  '    Property Target : String Read FTarget Write SetTarget;'#010+
+  '    Property OS : TOS Read FOS Write SetOS;'#010,
+  '    Property CPU : TCPU Read FCPU Write SetCPU;'#010+
+  '    Property Mode : TCompilerMode Read FMode Write FMode;'#010+
+  '    Property UnixPaths : Boolean Read FUnixPaths Write FUnixPaths;'#010+
+  '    Property Options : String Read FOptions Write FOptions;    // D','e'+
+  'fault compiler options.'#010+
+  '    Property SourceExt : String Read FSourceExt Write FSourceExt;'#010+
+  '    Property NoFPCCfg : Boolean Read FNoFPCCfg Write FNoFPCCfg;'#010+
+  '    // paths etc.'#010+
+  '    Property LocalUnitDir : String Read GetLocalUnitDir Write SetLo','c'+
+  'alUnitDir;'#010+
+  '    Property GlobalUnitDir : String Read GetGlobalUnitDir Write SetGlo'+
+  'balUnitDir;'#010+
+  '    Property Prefix : String Read FPrefix Write SetPrefix;'#010+
+  '    Property BaseInstallDir : String Read GetBaseInstallDir Write SetB'+
+  'aseInstallDir;'#010+
+  '  ','  Property UnitInstallDir : String Read GetUnitInstallDir Write FU'+
+  'nitInstallDir;'#010+
+  '    Property BinInstallDir : String Read GetBinInstallDir Write FBinIn'+
+  'stallDir;'#010+
+  '    Property DocInstallDir : String Read GetDocInstallDir Write FDocIn'+
+  'stallDir;',#010+
+  '    Property ExamplesInstallDir : String Read GetExamplesInstallDir Wr'+
+  'ite FExamplesInstallDir;'#010+
+  '    // Command tools. If not set, internal commands  will be used.'#010+
+  '    Property Compiler : String Read GetCompiler Write FCompiler; // Co'+
+  'mpiler.',' Defaults to fpc'#010+
+  '    Property Copy : String Read FCopy Write FCopy;             // copy'+
+  ' $(FILES) to $(DEST)'#010+
+  '    Property Move : String Read FMove Write FMove;             // Move'+
+  ' $(FILES) to $(DEST)'#010+
+  '    Property Remove : String Read FRemove',' Write FRemove;       // De'+
+  'lete $(FILES)'#010+
+  '    Property MkDir : String Read FMkDir write FMkDir;          // Make'+
+  ' $(DIRECTORY)'#010+
+  '    Property Archive : String Read FArchive Write FArchive;    // zip '+
+  '$(ARCHIVE) $(FILESORDIRS)'#010+
+  '  end;'#010+
+  #010+
+  '  { TBasicD','efaults }'#010+
+  #010+
+  '  TBasicDefaults = Class(TCustomDefaults)'#010+
+  '  end;'#010+
+  #010+
+  '  { TFPCDefaults }'#010+
+  #010+
+  '  TFPCDefaults = Class(TCustomDefaults)'#010+
+  '  public'#010+
+  '    procedure CompilerDefaults; override;'#010+
+  '  end;'#010+
+  #010+
+  '  { TBuildEngine }'#010+
+  #010+
+  '  TBuildEngine = Class(TComponent)'#010+
+  '  pri','vate'#010+
+  '    // general variables'#010+
+  '    FCompiler : String;'#010+
+  '    FStartDir : String;'#010+
+  '    FTargetDir : String;'#010+
+  '    FForceCompile : Boolean;'#010+
+  '    FListMode : Boolean;'#010+
+  '{$ifdef HAS_UNIT_ZIPPER}'#010+
+  '    FZipFile: TZipper;'#010+
+  '{$endif HAS_UNIT_ZIPPER}'#010+
+  '    FExter','nalPackages : TPackages;'#010+
+  '    // Events'#010+
+  '    FOnLog: TLogEvent;'#010+
+  '    FAfterArchive: TNotifyEvent;'#010+
+  '    FAfterClean: TNotifyEvent;'#010+
+  '    FAfterCompile: TNotifyEvent;'#010+
+  '    FAfterInstall: TNotifyEvent;'#010+
+  '    FAfterManifest: TNotifyEvent;'#010+
+  '    FBeforeArc','hive: TNotifyEvent;'#010+
+  '    FBeforeClean: TNotifyEvent;'#010+
+  '    FBeforeCompile: TNotifyEvent;'#010+
+  '    FBeforeInstall: TNotifyEvent;'#010+
+  '    FBeforeManifest: TNotifyEvent;'#010+
+  '    procedure SetTargetDir(const AValue: String);'#010+
+  '  Protected'#010+
+  '    Procedure Error(con','st Msg : String);'#010+
+  '    Procedure Error(const Fmt : String; const Args : Array of const);'#010+
+  '    // Internal copy/delete/move/archive/mkdir files'#010+
+  '    Function  SysDirectoryExists(const ADir:string):Boolean;'#010+
+  '    Function  SysFileExists(const AFil','eName:string):Boolean;'#010+
+  '    Procedure SysCopyFile(Const Src,Dest : String); virtual;'#010+
+  '    Procedure SysMoveFile(Const Src,Dest : String); virtual;'#010+
+  '    Procedure SysDeleteFile(Const AFileName : String); virtual;'#010+
+  '    Procedure SysArchiveFiles(L','ist : TStrings; Const AFileName : Str'+
+  'ing); virtual;'#010+
+  '    Procedure Log(Level : TVerboseLevel; Const Msg : String);'#010+
+  '    Procedure Log(Level : TVerboseLevel; Const Fmt : String; const Arg'+
+  's : Array Of Const);'#010+
+  '    Procedure EnterDir(ADir : Strin','g);'#010+
+  '    Function GetCompiler : String;'#010+
+  '    Function InstallPackageFiles(APAckage : TPackage; tt : TTargetType'+
+  '; Const Dest : String):Boolean;'#010+
+  '    Function FileNewer(const Src,Dest : String) : Boolean;'#010+
+  '    Procedure LogSearchPath(const ASearc','hPathName:string;Path:TCondi'+
+  'tionalStrings; ACPU:TCPU;AOS:TOS;Const PathPrefix :String='#039#039');'#010+
+  '    Function FindFileInPath(Path:TConditionalStrings; AFileName:String'+
+  '; var FoundPath:String;ACPU:TCPU;AOS:TOS; Const PathPrefix :String='#039+
+  #039'):Boolean;',#010+
+  #010+
+  '    //package commands'#010+
+  '    Procedure ResolveFileNames(APackage : TPackage; ACPU:TCPU;AOS:TOS)'+
+  ';'#010+
+  '    Function  GetOutputDir(AName: string; APackage : TPackage; Absolut'+
+  'ePath : Boolean = False) : String;'#010+
+  '    function  GetUnitDir(APackage:TPac','kage):String;'#010+
+  '    procedure AddDependencyUnitPaths(L:TStrings;APackage: TPackage);'#010+
+  '  Public'#010+
+  '    Constructor Create(AOwner : TComponent); override;'#010+
+  '    destructor Destroy;override;'#010+
+  '    // Public Copy/delete/Move/Archive/Mkdir Commands.'#010+
+  '    P','rocedure ExecuteCommand(const Cmd,Args : String; IgnoreError : '+
+  'Boolean = False); virtual;'#010+
+  '    Procedure CmdCopyFiles(List : TStrings; Const DestDir : String);'#010+
+  '    Procedure CmdCreateDir(const DestDir : String);'#010+
+  '    Procedure CmdMoveFiles(Li','st : TStrings; Const DestDir : String);'+
+  #010+
+  '    Procedure CmdDeleteFiles(List : TStrings);'#010+
+  '    Procedure CmdArchiveFiles(List : TStrings; Const ArchiveFile : Str'+
+  'ing);'#010+
+  '    Procedure ExecuteCommands(Commands : TCommands; At : TCommandAt);'#010+
+  '    // ','Dependency commands'#010+
+  '    Function  DependencyOK(ADependency : TDependency) : Boolean;'#010+
+  '    // Target commands'#010+
+  '    Function  GetTargetDir(APackage : TPackage; ATarget : TTarget; Abs'+
+  'olutePath : Boolean = False) : String;'#010+
+  '    Function  GetCompil','erCommand(APackage : TPackage; ATarget : TTar'+
+  'get) : String;'#010+
+  '    Function  TargetOK(ATarget : TTarget) : Boolean;'#010+
+  '    Function  NeedsCompile(APackage:TPackage; ATarget : TTarget) : Boo'+
+  'lean;'#010+
+  '    Procedure Compile(APackage:TPackage; ATarget : ','TTarget);  virtua'+
+  'l;'#010+
+  '    Procedure MaybeCompile(APackage:TPackage; ATarget: TTarget);'#010+
+  '    Procedure CompileDependencies(APackage:TPackage; ATarget: TTarget)'+
+  ';'#010+
+  '    // Package commands'#010+
+  '    Function  GetPackageDir(APackage : TPackage; AbsolutePa','th : Bool'+
+  'ean = False) : String;'#010+
+  '    Function  GetUnitsOutputDir(APackage : TPackage; AbsolutePath : Bo'+
+  'olean = False) : String;'#010+
+  '    Function  GetBinOutputDir(APackage : TPackage; AbsolutePath : Bool'+
+  'ean = False) : String;'#010+
+  '    Function  Packag','eOK(APackage : TPackage) : Boolean; virtual;'#010+
+  '    Procedure DoBeforeCompile(APackage : TPackage);virtual;'#010+
+  '    Procedure DoAfterCompile(APackage : TPackage);virtual;'#010+
+  '    Procedure DoBeforeInstall(APackage : TPackage);virtual;'#010+
+  '    Procedure Do','AfterInstall(APackage : TPackage);virtual;'#010+
+  '    Procedure DoBeforeArchive(APackage : TPackage);virtual;'#010+
+  '    Procedure DoAfterArchive(APackage : TPackage);virtual;'#010+
+  '    Procedure DoBeforeClean(APackage : TPackage);virtual;'#010+
+  '    Procedure DoAfte','rClean(APackage : TPackage);virtual;'#010+
+  '    Function NeedsCompile(APackage : TPackage) : Boolean; virtual;'#010+
+  '    Procedure Compile(APackage : TPackage);'#010+
+  '    Procedure Install(APackage : TPackage);'#010+
+  '    Procedure Archive(APackage : TPackage);'#010+
+  '    ','Procedure Clean(APackage : TPackage);'#010+
+  '    Procedure CompileDependencies(APackage : TPackage);'#010+
+  '    Procedure GetManifest(APackage : TPackage; Manifest : TStrings);'#010+
+  '    Function CheckExternalPackage(Const APackageName : String):TPackag'+
+  'e;'#010+
+  '    ','procedure CreateOutputDir(APackage: TPackage);'#010+
+  '    // Packages commands'#010+
+  '    Procedure Compile(Packages : TPackages);'#010+
+  '    Procedure Install(Packages : TPackages);'#010+
+  '    Procedure Archive(Packages : TPackages);'#010+
+  '    Procedure Clean(Packages : TP','ackages);'#010+
+  '    Procedure GetManifest(Packages : TPackages; Manifest : TStrings);'#010+
+  '    Property ListMode : Boolean Read FListMode Write FListMode;'#010+
+  '    Property ForceCompile : Boolean Read FForceCompile Write FForceCom'+
+  'pile;'#010+
+  '//    Property Defau','lts : TCustomDefaults Read FDefaults Write SetDe'+
+  'faults;'#010+
+  '    Property TargetDir : String Read FTargetDir Write SetTargetDir;'#010+
+  '    Property ExternalPackages: TPackages Read FExternalPackages;'#010+
+  '    // Events'#010+
+  '    Property BeforeCompile : TNotifyE','vent Read FBeforeCompile Write '+
+  'FBeforeCompile;'#010+
+  '    Property AfterCompile : TNotifyEvent Read FAfterCompile Write FAft'+
+  'erCompile;'#010+
+  '    Property BeforeInstall : TNotifyEvent Read FBeforeInstall Write FB'+
+  'eforeInstall;'#010+
+  '    Property AfterInstall : ','TNotifyEvent Read FAfterInstall Write FA'+
+  'fterInstall;'#010+
+  '    Property BeforeClean : TNotifyEvent Read FBeforeClean Write FBefor'+
+  'eClean;'#010+
+  '    Property AfterClean : TNotifyEvent Read FAfterClean Write FAfterCl'+
+  'ean;'#010+
+  '    Property BeforeArchive : TNoti','fyEvent Read FBeforeArchive Write '+
+  'FBeforeArchive;'#010+
+  '    Property AfterArchive : TNotifyEvent Read FAfterArchive Write FAft'+
+  'erArchive;'#010+
+  '    Property BeforeManifest : TNotifyEvent Read FBeforeManifest Write '+
+  'FBeforeManifest;'#010+
+  '    Property AfterMani','fest : TNotifyEvent Read FAfterManifest Write '+
+  'FAfterManifest;'#010+
+  '    Property OnLog : TLogEvent Read FOnLog Write FOnlog;'#010+
+  '  end;'#010+
+  #010+
+  '  { TCustomInstaller }'#010+
+  #010+
+  '  TCustomInstaller = Class(TComponent)'#010+
+  '  private'#010+
+  '    FBuildEngine: TBuildEngine;'#010+
+  '    FPac','kages: TPackages;'#010+
+  '    FRunMode: TRunMode;'#010+
+  '    FListMode : Boolean;'#010+
+  '    FLogLevels : TVerboseLevels;'#010+
+  '  Protected'#010+
+  '    Procedure Log(Level : TVerboseLevel; Const Msg : String);'#010+
+  '    Procedure CreatePackages; virtual;'#010+
+  '    Procedure CheckPackages','; virtual;'#010+
+  '    Procedure CreateBuildEngine; virtual;'#010+
+  '    Procedure Error(const Msg : String);'#010+
+  '    Procedure Error(const Fmt : String; Args : Array of const);'#010+
+  '    Procedure AnalyzeOptions;'#010+
+  '    Procedure Usage(const FMT : String; Args : Array',' of const);'#010+
+  '    Procedure Compile(Force : Boolean); virtual;'#010+
+  '    Procedure Clean; virtual;'#010+
+  '    Procedure Install; virtual;'#010+
+  '    Procedure Archive; virtual;'#010+
+  '    Procedure Manifest; virtual;'#010+
+  '    Property BuildEngine : TBuildEngine Read FBuildE','ngine;'#010+
+  '  Public'#010+
+  '    Constructor Create(AOwner : TComponent); virtual;'#010+
+  '    Destructor destroy; override;'#010+
+  '    Function AddPackage(Const AName : String) : TPackage;'#010+
+  '    Function Run : Boolean;'#010+
+  '    //files in package'#010+
+  '    Property Packages : TPa','ckages Read FPackages;'#010+
+  '    Property RunMode : TRunMode Read FRunMode;'#010+
+  '    Property ListMode : Boolean Read FListMode;'#010+
+  '  end;'#010+
+  #010+
+  '  { TFPCInstaller }'#010+
+  '  TFPCInstaller = class(TCustomInstaller)'#010+
+  '  public'#010+
+  '    Constructor Create(AOwner : TComponent)','; override;'#010+
+  '  end;'#010+
+  #010+
+  '  { TBasicInstaller }'#010+
+  '  TBasicInstaller = class(TCustomInstaller)'#010+
+  '    Constructor Create(AOwner : TComponent); override;'#010+
+  '  end;'#010+
+  #010+
+  '  TReplaceFunction = Function (Const AName,Args : String) : String of '+
+  'Object;'#010+
+  #010+
+  '  { TValueIt','em }'#010+
+  #010+
+  '  TValueItem = Class(TObject)'#010+
+  '    FValue : String;'#010+
+  '    Constructor Create(AValue : String);'#010+
+  '  end;'#010+
+  #010+
+  '  { TFunctionItem }'#010+
+  #010+
+  '  TFunctionItem = Class(TObject)'#010+
+  '    FFunc : TReplaceFunction;'#010+
+  '    Constructor Create(AFunc : TReplaceFunction);'#010,
+  '  end;'#010+
+  #010+
+  '  { TDictionary }'#010+
+  #010+
+  '  TDictionary = Class(TComponent)'#010+
+  '    FList : TStringList;'#010+
+  '  Public'#010+
+  '    Constructor Create(AOwner : TComponent); override;'#010+
+  '    Destructor Destroy;override;'#010+
+  '    Procedure AddVariable(Const AName,Value : String);'#010+
+  '  ','  Procedure AddFunction(Const AName : String; FReplacement : TRepl'+
+  'aceFunction);'#010+
+  '    Procedure RemoveItem(Const AName : String);'#010+
+  '    Function GetValue(Const AName : String) : String;'#010+
+  '    Function GetValue(Const AName,Args : String) : String;',' virtual;'#010+
+  '    Function ReplaceStrings(Const ASource : String) : String; virtual;'+
+  #010+
+  '  end;'#010+
+  #010+
+  '  ECollectionError = Class(Exception);'#010+
+  '  EDictionaryError = Class(Exception);'#010+
+  '  EInstallerError = Class(Exception);'#010+
+  #010+
+  '  TInstallerClass = Class of TCust','omInstaller;'#010+
+  '  TDictionaryClass = Class of TDictionary;'#010+
+  #010+
+  'Type'#010+
+  '  TArchiveEvent = Procedure (Const AFileName : String; List : TStrings'+
+  ') of Object;'#010+
+  '  TArchiveProc = Procedure (Const AFileName : String; List : TStrings)'+
+  ';'#010+
+  #010+
+  'Var'#010+
+  '  DictionaryClass ',': TDictionaryClass = TDictionary;'#010+
+  '  OnArchiveFiles : TArchiveEvent = Nil;'#010+
+  '  ArchiveFilesProc : TArchiveProc = Nil;'#010+
+  #010+
+  '  Defaults : TCustomDefaults; // Set by installer.'#010+
+  '  Dictionary : TDictionary;'#010+
+  #010+
+  #010+
+  'Function CurrentOS : String;'#010+
+  'Function Curre','ntCPU : String;'#010+
+  #010+
+  'Function Installer(InstallerClass: TInstallerClass) : TCustomInstaller'+
+  '; overload;'#010+
+  'Function Installer : TCustomInstaller; overload;'#010+
+  #010+
+  'Function OSToString(OS: TOS) : String;'#010+
+  'Function OSesToString(OSes: TOSes) : String;'#010+
+  'Functio','n CPUToString(CPU: TCPU) : String;'#010+
+  'Function CPUSToString(CPUS: TCPUS) : String;'#010+
+  'Function StringToOS(const S : String) : TOS;'#010+
+  'Function OSesToString(const S : String) : TOSes;'#010+
+  'Function StringToCPU(const S : String) : TCPU;'#010+
+  'Function StringToCP','US(const S : String) : TCPUS;'#010+
+  'Function ModeToString(Mode: TCompilerMode) : String;'#010+
+  'Function StringToMode(const S : String) : TCompilerMode;'#010+
+  'Function MakeTargetString(CPU : TCPU;OS: TOS) : String;'#010+
+  'Procedure StringToCPUOS(const S : String; Va','r CPU : TCPU; Var OS: TO'+
+  'S);'#010+
+  'Function FixPath (const APath : String) : String;'#010+
+  'Procedure ChangeDir(const APath : String);'#010+
+  'Function Substitute(Const Source : String; Macros : Array of string) :'+
+  ' String;'#010+
+  'Procedure SplitCommand(Const Cmd : Strin','g; Var Exe,Options : String)'+
+  ';'#010+
+  #010+
+  'Implementation'#010+
+  #010+
+  'uses typinfo;'#010+
+  #010+
+  'ResourceString'#010+
+  '  SErrInvalidCPU        = '#039'Invalid CPU name "%s"'#039';'#010+
+  '  SErrInvalidOS         = '#039'Invalid OS name "%s"'#039';'#010+
+  '  SErrInvalidMode       = '#039'Invalid compiler mode "%s"'#039';'#010+
+  '  SErr','InvalidTarget     = '#039'Invalid compiler target "%s"'#039';'#010+
+  '  SErrNameExists        = '#039'Name "%s" already exists in the collect'+
+  'ion.'#039';'#010+
+  '  SErrNoSuchName        = '#039'Could not find item with name "%s" in t'+
+  'he collection.'#039';'#010+
+  '  SErrInValidArgument   = '#039'Inval','id command-line argument at posi'+
+  'tion %d: %s'#039';'#010+
+  '  SErrNeedArgument      = '#039'Option at position %d (%s) needs an arg'+
+  'ument'#039';'#010+
+  '  SErrNoPackagesDefined = '#039'No action possible: No packages were de'+
+  'fined.'#039';'#010+
+  '  SErrInstaller         = '#039'The installer enco','untered the followi'+
+  'ng error:'#039';'#010+
+  '  SErrDepUnknownTarget  = '#039'Unknown target in dependencies for %s: '+
+  '%s'#039';'#010+
+  '  SErrExternalCommandFailed = '#039'External command "%s" failed with e'+
+  'xit code %d'#039';'#010+
+  '  SErrCreatingDirectory = '#039'Failed to create directory "%s"',#039';'#010+
+  '  SErrDeletingFile      = '#039'Failed to delete file "%s"'#039';'#010+
+  '  SErrMovingFile        = '#039'Failed to move file "%s" to "%s"'#039';'#010+
+  '  SErrCopyingFile       = '#039'Failed to copy file "%s" to "%s"'#039';'#010+
+  '  SErrChangeDirFailed   = '#039'Failed to enter directory "%s"',#039';'#010+
+  '  SErrInvalidArgumentToSubstitute = '#039'Invalid number of arguments t'+
+  'o Substitute'#039';'#010+
+  '  SErrNoArchiveSupport  = '#039'This binary contains no archive support'+
+  '. Please recompile with archive support'#039';'#010+
+  '  SErrNoDictionaryItem  = '#039'No item called "%s" i','n the dictionary'+
+  #039';'#010+
+  '  SErrNoDictionaryValue = '#039'The item "%s" in the dictionary is not '+
+  'a value.'#039';'#010+
+  '  SErrNoDictionaryFunc  = '#039'The item "%s" in the dictionary is not '+
+  'a function.'#039';'#010+
+  '  SErrInvalidFPCInfo    = '#039'Compiler returns invalid information,',' '+
+  'check if fpc -iV works'#039';'#010+
+  '  SErrDependencyNotFound = '#039'Could not find unit directory for depe'+
+  'ndency package "%s"'#039';'#010+
+  '  SErrAlreadyInitialized = '#039'Installer can only be initialized once'+
+  #039';'#010+
+  #010+
+  '  SWarnCircularDependency = '#039'Warning: Circular dependenc','y detect'+
+  'ed when compiling target %s with target %s'#039';'#010+
+  '  SWarnFailedToSetTime    = '#039'Warning: Failed to set timestamp on f'+
+  'ile "%s"'#039';'#010+
+  '  SWarnFailedToGetTime    = '#039'Warning: Failed to get timestamp from'+
+  ' file "%s"'#039';'#010+
+  '  SWarnFileDoesNotExist   = '#039'Wa','rning: File "%s" does not exist'#039+
+  ';'#010+
+  '  SWarnAttemptingToCompileNonNeutralTarget = '#039'Attempting to compil'+
+  'e non-neutral target %s'#039';'#010+
+  #010+
+  '  SInfoEnterDir           = '#039'Entering directory "%s"'#039';'#010+
+  '  SInfoCompilingPackage   = '#039'Compiling package %s'#039';'#010+
+  '  SInf','oCompilingTarget    = '#039'Compiling target %s'#039';'#010+
+  '  SInfoExecutingCommand   = '#039'Executing command "%s %s"'#039';'#010+
+  '  SInfoCreatingOutputDir  = '#039'Creating output dir "%s"'#039';'#010+
+  '  SInfoInstallingPackage  = '#039'Installing package %s'#039';'#010+
+  '  SInfoArchivingPackage   = '#039,'Archiving package %s'#039';'#010+
+  '  SInfoArchivingFile      = '#039'Archiving "%s"'#039';'#010+
+  '  SInfoCleaningPackage    = '#039'Cleaning package %s'#039';'#010+
+  '  SInfoCopyingFile        = '#039'Copying file "%s" to "%s"'#039';'#010+
+  '  SInfoSourceNewerDest    = '#039'Source file "%s" (%s) is newer tha','n'+
+  ' destination "%s" (%s).'#039';'#010+
+  #010+
+  '  SDbgComparingFileTimes    = '#039'Comparing file "%s" time "%s" to "%'+
+  's" time "%s".'#039';'#010+
+  '  SDbgCompilingDependenciesOfTarget = '#039'Compiling dependencies of t'+
+  'arget %s'#039';'#010+
+  '  SDbgResolvingSourcesOfTarget = '#039'Resolving filenames',' of target '+
+  '%s'#039';'#010+
+  '  SDbgResolvedSourceFile    = '#039'Resolved source file %s to "%s"'#039+
+  ';'#010+
+  '  SDbgResolvedIncludeFile   = '#039'Resolved include file %s to "%s"'#039+
+  ';'#010+
+  '  SDbgOutputNotYetAvailable = '#039'Output file %s not available'#039';'#010+
+  '  SDbgDependencyOnUnit      = '#039,'Dependency of %s on unit %s'#039';'#010+
+  '  SDbgDependencyUnitRecompiled = '#039'Dependent unit %s is being recom'+
+  'piled'#039';'#010+
+  '  SDbgMustCompile           = '#039'Must compile %s'#039';'#010+
+  '  SDbgTargetHasWrongOS      = '#039'Target has wrong OS: %s'#039';'#010+
+  '  SDbgTargetHasWrongCPU     = ',#039'Target has wrong CPU: %s'#039';'#010+
+  '  SDbgTargetIsNotAUnitOrProgram = '#039'Skipping Target %s, not an unit'+
+  ' or program'#039';'#010+
+  '  SDbgConsideringTarget     = '#039'Considering target %s'#039';'#010+
+  '  SDbgConsideringPackage    = '#039'Considering package %s'#039';'#010+
+  '  SDbgExternalDepende','ncy    = '#039'External dependency %s found in "'+
+  '%s"'#039';'#010+
+  '  SDbgBuildEngineArchiving  = '#039'Build engine archiving.'#039';'#010+
+  '  SDbgBuildEngineCleaning   = '#039'Build engine cleaning.'#039';'#010+
+  '  SDbgGenerating            = '#039'Generating "%s"'#039';'#010+
+  '  SDbgLoading               =',' '#039'Loading "%s"'#039';'#010+
+  '  SDbgFound                 = '#039'Found'#039';'#010+
+  '  SDbgNotFound              = '#039'Not Found'#039';'#010+
+  '  SDbgDirectoryExists       = '#039'Directory "%s" %s'#039';'#010+
+  '  SDbgFileExists            = '#039'File "%s" %s'#039';'#010+
+  '  SDbgSearchPath            = '#039'Using %s path',' "%s"'#039';'#010+
+  #010+
+  '  // Help messages for usage'#010+
+  '  SValue              = '#039'Value'#039';'#010+
+  '  SHelpUsage          = '#039'Usage: %s command [options]'#039';'#010+
+  '  SHelpCommand        = '#039'Where command is one of the following:'#039+
+  ';'#010+
+  '  SHelpCompile        = '#039'Compile all units in th','e package(s).'#039+
+  ';'#010+
+  '  SHelpBuild          = '#039'Build all units in the package(s).'#039';'#010+
+  '  SHelpInstall        = '#039'Install all units in the package(s).'#039';'+
+  #010+
+  '  SHelpClean          = '#039'Clean (remove) all units in the package(s'+
+  ').'#039';'#010+
+  '  SHelpArchive        = '#039'Cr','eate archive (zip) with all units in '+
+  'the package(s).'#039';'#010+
+  '  SHelpHelp           = '#039'This message.'#039';'#010+
+  '  SHelpManifest       = '#039'Create a manifest suitable for import in '+
+  'repository.'#039';'#010+
+  '  SHelpCmdOptions     = '#039'Where options is one or more of the fol','l'+
+  'owing:'#039';'#010+
+  '  SHelpCPU            = '#039'Compile for indicated CPU.'#039';'#010+
+  '  SHelpOS             = '#039'Compile for indicated OS'#039';'#010+
+  '  SHelpTarget         = '#039'Compile for indicated target'#039';'#010+
+  '  SHelpList           = '#039'list commands instead of actually executi'+
+  'ng',' them.'#039';'#010+
+  '  SHelpPrefix         = '#039'Use indicated prefix directory for all co'+
+  'mmands.'#039';'#010+
+  '  SHelpNoFPCCfg       = '#039'Compiler will not use fpc.cfg'#039';'#010+
+  '  SHelpBaseInstallDir = '#039'Use indicated directory as base install d'+
+  'ir.'#039';'#010+
+  '  SHelpLocalUnitDir   = '#039'U','se indicated directory as local (user)'+
+  ' unit dir.'#039';'#010+
+  '  SHelpGlobalUnitDir  = '#039'Use indicated directory as global unit di'+
+  'r.'#039';'#010+
+  '  SHelpCompiler       = '#039'Use indicated binary as compiler'#039';'#010+
+  '  SHelpConfig         = '#039'Use indicated config file when co','mpilin'+
+  'g.'#039';'#010+
+  '  SHelpVerbose        = '#039'Be verbose when working.'#039';'#010+
+  #010+
+  #010+
+  'Const'#010+
+  '  // Keys for Defaults file. Do not localize.'#010+
+  '  KeyCompiler = '#039'Compiler'#039';'#010+
+  '  KeyArchive  = '#039'Archive'#039';'#010+
+  '  KeyCopy     = '#039'Copy'#039';'#010+
+  '  KeyMkDir    = '#039'MkDir'#039';'#010+
+  '  KeyMove     = '#039'Mo','ve'#039';'#010+
+  '  KeyRemove   = '#039'Remove'#039';'#010+
+  '  KeyOptions  = '#039'Options'#039';'#010+
+  '  KeyCPU      = '#039'CPU'#039';'#010+
+  '  KeyOS       = '#039'OS'#039';'#010+
+  '  KeyMode     = '#039'Mode'#039';'#010+
+  '  KeyPrefix   = '#039'Prefix'#039';'#010+
+  '  KeyTarget   = '#039'Target'#039';'#010+
+  '  KeyNoFPCCfg = '#039'NoFPCCfg'#039';'#010+
+  '  KeyLocalUnitDir       = '#039'LocalU','nitDir'#039';'#010+
+  '  KeyGlobalUnitDir      = '#039'GlobalUnitDir'#039';'#010+
+  '  KeyBaseInstallDir     = '#039'BaseInstallDir'#039';'#010+
+  '  KeyUnitInstallDir     = '#039'UnitInstallDir'#039';'#010+
+  '  KeyBinInstallDir      = '#039'BinInstallDir'#039';'#010+
+  '  KeyDocInstallDir      = '#039'DocInstallDir'#039';'#010+
+  '  KeyExamplesI','nstallDir = '#039'ExamplesInstallDir'#039';'#010+
+  '  KeySourceExt = '#039'SourceExt'#039';'#010+
+  '  // Keys for unit config'#010+
+  '  KeyName     = '#039'Name'#039';'#010+
+  '  KeyVersion  = '#039'Version'#039';'#010+
+  '  KeyNeedLibC = '#039'NeedLibC'#039';'#010+
+  '  KeyDepends  = '#039'Depends'#039';'#010+
+  #010+
+  '{******************************************','*************************'+
+  '*********'#010+
+  '                                Helpers'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  #010+
+  'Procedure SplitVersion(AValue: String; Var Release,Major,Minor : Word;'+
+  ' Var Suffix : S','tring);'#010+
+  #010+
+  '  Function NextDigit(sep : Char; var V : string) : integer;'#010+
+  '  Var'#010+
+  '    P : Integer;'#010+
+  '  begin'#010+
+  '    P:=Pos(Sep,V);'#010+
+  '    If (P=0) then'#010+
+  '      P:=Length(V)+1;'#010+
+  '    Result:=StrToIntDef(Copy(V,1,P-1),-1);'#010+
+  '    If Result<>-1 then'#010+
+  '      Delete(V,','1,P)'#010+
+  '    else'#010+
+  '      Result:=0;'#010+
+  '  end;'#010+
+  #010+
+  'Var'#010+
+  '  P : Integer;'#010+
+  '  V : String;'#010+
+  'begin'#010+
+  '  Release:=0;'#010+
+  '  Major:=0;'#010+
+  '  Minor:=0;'#010+
+  '  Suffix:='#039#039';'#010+
+  '  V:=AValue;'#010+
+  '  Release:=NextDigit('#039'.'#039',V);'#010+
+  '  Major:=NextDigit('#039'.'#039',V);'#010+
+  '  Minor:=NextDigit('#039'-'#039',V);'#010+
+  '  P:=Pos('#039'-'#039',V',');'#010+
+  '  If (P<>0) then'#010+
+  '    Delete(V,1,P);'#010+
+  '  Suffix:=V;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function QuoteXML(S : String) : string;'#010+
+  #010+
+  '  Procedure W(Var J : Integer; Var R : String; T : String);'#010+
+  '  Var'#010+
+  '    I: integer;'#010+
+  '  begin'#010+
+  '    If J+Length(T)>Length(R) then'#010+
+  '      SetLength(','R,J+Length(T));'#010+
+  '    For I:=1 to Length(t) do'#010+
+  '      begin'#010+
+  '      R[J]:=T[i];'#010+
+  '      If I<Length(T) then'#010+
+  '        Inc(J);'#010+
+  '      end;'#010+
+  '  end;'#010+
+  #010+
+  'const'#010+
+  '  QuotStr = '#039'&quot;'#039';'#010+
+  '  AmpStr = '#039'&amp;'#039';'#010+
+  '  ltStr = '#039'&lt;'#039';'#010+
+  '  gtStr = '#039'&gt;'#039';'#010+
+  'Var'#010+
+  '  I,J : Integer;',#010+
+  'begin'#010+
+  '  SetLength(Result,Length(S));'#010+
+  '  J:=0;'#010+
+  '  For I:=1 to Length(S) do'#010+
+  '    begin'#010+
+  '    Inc(J);'#010+
+  '    case S[i] of'#010+
+  '      '#039'"'#039': W(j,Result,QuotStr);'#010+
+  '      '#039'&'#039': W(J,Result,AmpStr);'#010+
+  '      '#039'<'#039': W(J,Result,ltStr);'#010+
+  '      '#039'>'#039': W(J,Result,gtStr);'#010+
+  '     ',' // Escape whitespace using CharRefs to be consistent with W3 s'+
+  'pec X 3.3.3'#010+
+  '       #9: w(J,Result,'#039'&#x9;'#039');'#010+
+  '{      #10: wrtStr('#039'&#xA;'#039');'#010+
+  '       #13: wrtStr('#039'&#xD;'#039');}'#010+
+  '    else'#010+
+  '      Result[J]:=S[i];'#010+
+  '    end;'#010+
+  '    If (J=Length(Result)) and (I<','Length(S)) then'#010+
+  '      SetLength(Result,J+Length(S)-I);'#010+
+  '    end;'#010+
+  '  If J<>Length(Result) then'#010+
+  '    SetLength(Result,J);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '// Callback for Sysutils getapplicationname.'#010+
+  'Function GetFPMakeName : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:='#039'fpmake'#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Func','tion CurrentOS : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=OSToString(Defaults.OS);'#010+
+  'end;'#010+
+  #010+
+  'Function CurrentCPU : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=CPUToString(Defaults.CPU);'#010+
+  'end;'#010+
+  #010+
+  'Function OSToString(OS: TOS) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=LowerCase(GetenumName(TypeInfo(','TOS),Ord(OS)));'#010+
+  'end;'#010+
+  #010+
+  'Function OSesToString(OSes: TOSes) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=LowerCase(SetToString(PtypeInfo(TypeInfo(TOSes)),Integer(OSe'+
+  's),False));'#010+
+  'end;'#010+
+  #010+
+  'Function CPUToString(CPU: TCPU) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=LowerCase(GetenumNa','me(TypeInfo(TCPU),Ord(CPU)));'#010+
+  'end;'#010+
+  #010+
+  'Function CPUSToString(CPUS: TCPUS) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=LowerCase(SetToString(PTypeInfo(TypeInfo(TCPUS)),Integer(CPU'+
+  'S),False));'#010+
+  'end;'#010+
+  #010+
+  'Function StringToOS(const S : String) : TOS;'#010+
+  #010+
+  'Var'#010+
+  '  I : Integer;',#010+
+  #010+
+  'begin'#010+
+  '  I:=GetEnumValue(TypeInfo(TOS),S);'#010+
+  '  if (I=-1) then'#010+
+  '    Raise EInstallerError.CreateFmt(SErrInvalidOS,[S]);'#010+
+  '  Result:=TOS(I);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function OSesToString(const S : String) : TOSes;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=TOSes(StringToSet(PTypeInfo(Type','Info(TOSes)),S));'#010+
+  'end;'#010+
+  #010+
+  'Function StringToCPU(const S : String) : TCPU;'#010+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  #010+
+  'begin'#010+
+  '  I:=GetEnumValue(TypeInfo(TCPU),S);'#010+
+  '  if (I=-1) then'#010+
+  '    Raise EInstallerError.CreateFmt(SErrInvalidCPU,[S]);'#010+
+  '  Result:=TCPU(I);'#010+
+  'end;'#010+
+  #010+
+  'Functi','on StringToCPUS(const S : String) : TCPUS;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=TCPUS(StringToSet(PTypeInfo(TypeInfo(TCPUS)),S));'#010+
+  'end;'#010+
+  #010+
+  'Function ModeToString(Mode: TCompilerMode) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=LowerCase(GetenumName(TypeInfo(TCompilerMode),Ord(Mode',')));'+
+  #010+
+  '  Delete(Result,1,2);'#010+
+  'end;'#010+
+  #010+
+  'Function StringToMode(const S : String) : TCompilerMode;'#010+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  #010+
+  'begin'#010+
+  '  I:=GetEnumValue(TypeInfo(TCompilerMode),S);'#010+
+  '  if (I=-1) then'#010+
+  '    Raise EInstallerError.CreateFmt(SErrInvalidMode,[S]);'#010+
+  '  ','Result:=TCompilerMode(I);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function MakeTargetString(CPU : TCPU;OS: TOS) : String;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=CPUToString(CPU)+'#039'-'#039'+OSToString(OS);'#010+
+  'end;'#010+
+  #010+
+  'Procedure StringToCPUOS(const S : String; Var CPU : TCPU; Var OS: TOS)'+
+  ';'#010+
+  #010+
+  'Var'#010+
+  '  P : integer;',#010+
+  #010+
+  'begin'#010+
+  '  P:=Pos('#039'-'#039',S);'#010+
+  '  If (P=0) then'#010+
+  '    Raise EInstallerError.CreateFmt(SErrInvalidTarget,[S]);'#010+
+  '  CPU:=StringToCPU(Copy(S,1,P-1));'#010+
+  '  OS:=StringToOs(Copy(S,P+1,Length(S)-P));'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure ResolveDependencies(L : TDependencies; P : T','NamedCollectio'+
+  'n);'#010+
+  'Var'#010+
+  '  I,J : Integer;'#010+
+  '  C : TDependency;'#010+
+  'begin'#010+
+  '  If Assigned(L) then'#010+
+  '    For I:=0 to L.Count-1 do'#010+
+  '      begin'#010+
+  '        C:=L[i];'#010+
+  '        if C.DependencyType in [depPackage,depUnit] then'#010+
+  '          begin'#010+
+  '            J:=P.IndexO','fName(C.Value);'#010+
+  '            If J<>-1 then'#010+
+  '              C.Target:=P.Items[J];'#010+
+  '          end;'#010+
+  '      end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function AddConditionalStrings(Dest : TStrings; Src : TConditionalStri'+
+  'ngs;ACPU:TCPU;AOS:TOS; Const APrefix : String='#039#039') : Integer',' ;'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  C : TConditionalString;'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  Result:=0;'#010+
+  '  Dictionary.AddVariable('#039'CPU'#039',CPUToString(ACPU));'#010+
+  '  Dictionary.AddVariable('#039'OS'#039',OSToString(AOS));'#010+
+  '  For I:=0 to Src.Count-1 do'#010+
+  '    begin'#010+
+  '      C:=Src[I];'#010+
+  '    ','  if (ACPU in C.CPUs) and (AOS in C.OSes) then'#010+
+  '        begin'#010+
+  '          If (APrefix<>'#039#039') then'#010+
+  '            S:=APrefix+C.Value'#010+
+  '          else'#010+
+  '            S:=C.Value;'#010+
+  '          Dest.Add(Dictionary.ReplaceStrings(S));'#010+
+  '          Inc(Result);'#010+
+  '    ','    end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure AddConditionalStrings(Var S : String; Src : TConditionalStri'+
+  'ngs;ACPU:TCPU;AOS:TOS; const APrefix : String='#039#039');'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  C : TConditionalString;'#010+
+  'begin'#010+
+  '  Dictionary.AddVariable('#039'CPU'#039',CPUToString(','ACPU));'#010+
+  '  Dictionary.AddVariable('#039'OS'#039',OSToString(AOS));'#010+
+  '  For I:=0 to Src.Count-1 do'#010+
+  '    begin'#010+
+  '      C:=Src[I];'#010+
+  '      if (ACPU in C.CPUs) and (AOS in C.OSes) then'#010+
+  '        begin'#010+
+  '          if (S<>'#039#039') then'#010+
+  '            S:=S+'#039' '#039';'#010+
+  '          S:=S+','APrefix+Dictionary.ReplaceStrings(C.Value);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function FileListToString(List : TStrings; const APrefix : String) : S'+
+  'tring;'#010+
+  'Var'#010+
+  '  I : integer;'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  Result:='#039#039';'#010+
+  '  For I:=0 to List.Count-1 do'#010+
+  '    beg','in'#010+
+  '      If (I>0) then'#010+
+  '        Result:=Result+'#039' '#039';'#010+
+  '      S:=APrefix+List[i];'#010+
+  '      If (Pos('#039' '#039',S)<>0) then'#010+
+  '        S:='#039'"'#039'+S+'#039'"'#039';'#010+
+  '      Result:=Result+S;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function FixPath (const APath : String) : String;'#010+
+  'Var'#010+
+  '  P : PChar;'#010+
+  'begi','n'#010+
+  '  Result:=APath;'#010+
+  '  If (result<>'#039#039') then'#010+
+  '    begin'#010+
+  '      P:=PChar(Result);'#010+
+  '      While (P^<>#0) do'#010+
+  '        begin'#010+
+  '          If P^ in ['#039'/'#039','#039'\'#039'] then'#010+
+  '            P^:=PathDelim;'#010+
+  '          Inc(P);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure ChangeDi','r(const APath : String);'#010+
+  'begin'#010+
+  '  if Not SetCurrentDir(APath) then'#010+
+  '    Raise EInstallerError.CreateFmt(SErrChangeDirFailed,[APath]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure SearchFiles(const AFileName: string; Recursive: boolean; var'+
+  ' List: TStrings);'#010+
+  #010+
+  '  procedure ','AddRecursiveFiles(const SearchDir, FileMask: string; Rec'+
+  'ursive: boolean);'#010+
+  '  const'#010+
+  '    IgnoreCase = {$ifdef UNIX}False{$else}True{$endif};'#010+
+  '  var'#010+
+  '    Info : TSearchRec;'#010+
+  '  begin'#010+
+  '    if FindFirst(SearchDir+'#039'*'#039',faAnyFile and faDirectory,Info)'+
+  '=0 ','then'#010+
+  '    begin'#010+
+  '      repeat'#010+
+  '          if ((Info.Attr and faDirectory) = faDirectory) and (Info.Nam'+
+  'e <> '#039'.'#039') and (Info.Name <> '#039'..'#039') and (Recursive) then'+
+  #010+
+  '            AddRecursiveFiles(SearchDir + Info.Name + PathDelim, FileM'+
+  'ask, Recursive);'#010,
+  '          if ((Info.Attr and faDirectory) <> faDirectory) and IsWild(I'+
+  'nfo.Name, FileMask, IgnoreCase) then'#010+
+  '            List.Add(SearchDir + Info.Name);'#010+
+  '      until FindNext(Info)<>0;'#010+
+  '    end;'#010+
+  '    FindClose(Info);'#010+
+  '  end;'#010+
+  #010+
+  'var'#010+
+  '  CurrDir,'#010+
+  '  Ba','sePath: string;'#010+
+  '  i: integer;'#010+
+  'begin'#010+
+  '  BasePath := ExtractFilePath(ExpandFileName(AFileName));'#010+
+  '  AddRecursiveFiles(BasePath, ExtractFileName(AFileName), Recursive);'#010+
+  #010+
+  '  CurrDir:=GetCurrentDir;'#010+
+  '  for i := 0 to Pred(List.Count) do'#010+
+  '    List[i] :','= ExtractRelativepath(CurrDir, List[i]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure SplitCommand(const Cmd : String; var Exe, Options : String);'+
+  #010+
+  #010+
+  'Const'#010+
+  '  WhiteSpace = [#9,#10,#13,'#039' '#039'];'#010+
+  '  QuoteChars = ['#039#039#039#039','#039'"'#039'];'#010+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  InQuote : Boolean;'#010+
+  '  LastQuote :',' Char;'#010+
+  '  S : String;'#010+
+  #010+
+  'begin'#010+
+  '  S:=Trim(Cmd);'#010+
+  '  InQuote:=False;'#010+
+  '  LastQuote:=#0;'#010+
+  '  I:=1;'#010+
+  '  While (I<=Length(S)) and (Inquote or not (S[I] in whiteSpace)) do'#010+
+  '    begin'#010+
+  '    If S[i] in QuoteChars then'#010+
+  '      begin'#010+
+  '      InQuote:=Not (S[i]=LastQuo','te);'#010+
+  '      If InQuote then'#010+
+  '         LastQuote:=S[i]'#010+
+  '       else'#010+
+  '         LastQuote:=#0;'#010+
+  '      end;'#010+
+  '    Inc(I);'#010+
+  '    end;'#010+
+  '  Exe:=Copy(S,1,I-1);'#010+
+  '  Delete(S,1,I);'#010+
+  '  Options:=Trim(S);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{$ifdef HAS_UNIT_PROCESS}'#010+
+  'function GetCompilerInfo(con','st ACompiler,AOptions:string):string;'#010+
+  'const'#010+
+  '  BufSize = 1024;'#010+
+  'var'#010+
+  '  S: TProcess;'#010+
+  '  Buf: array [0..BufSize - 1] of char;'#010+
+  '  Count: longint;'#010+
+  'begin'#010+
+  '  S:=TProcess.Create(Nil);'#010+
+  '  S.Commandline:=ACompiler+'#039' '#039'+AOptions;'#010+
+  '  S.Options:=[poUsePipes];'#010+
+  ' ',' S.execute;'#010+
+  '  Count:=s.output.read(buf,BufSize);'#010+
+  '  S.Free;'#010+
+  '  SetLength(Result,Count);'#010+
+  '  Move(Buf,Result[1],Count);'#010+
+  'end;'#010+
+  '{$endif HAS_UNIT_PROCESS}'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '              ','                  TNamedItem'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'procedure TNamedItem.SetName(const AValue: String);'#010+
+  #010+
+  'begin'#010+
+  '  if FName=AValue then exit;'#010+
+  '  With TNamedCollection(Collection) do'#010+
+  '    I','f UniqueNames then'#010+
+  '      If (IndexOfName(AVAlue)<>-1) then'#010+
+  '        Raise ECollectionError.CreateFmt(SErrNameExists,[AValue]);'#010+
+  '  FName:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '            ','                    TNamedCollection'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'function TNamedCollection.IndexOfName(const AName: String): Integer;'#010+
+  #010+
+  'begin'#010+
+  '  Result:=Count-1;'#010+
+  '  While (Result>=0) and (Comp','areText(TNamedItem(Items[Result]).FName'+
+  ',AName)<>0) do'#010+
+  '    Dec(Result);'#010+
+  'end;'#010+
+  #010+
+  'function TNamedCollection.ItemByName(const AName: String): TNamedItem;'+
+  #010+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  #010+
+  'begin'#010+
+  '  I:=IndexOfName(AName);'#010+
+  '  If (I=-1) Then'#010+
+  '    Raise ECollectionEr','ror.CreateFmt(SErrNoSuchName,[AName]);'#010+
+  '  Result:=TNamedItem(Items[i]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                             TNamedItemList'#010+
+  '****************************************','****************************'+
+  '********}'#010+
+  #010+
+  'function TNamedItemList.GetNamedItem(Index : Integer): TNamedItem;'#010+
+  'begin'#010+
+  '  Result:=TNamedItem(Items[Index]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TNamedItemList.SetNamedItem(Index : Integer; const AValue: T'+
+  'NamedItem);'#010+
+  'beg','in'#010+
+  '  Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TNamedItemList.IndexOfName(const AName: String): Integer;'#010+
+  'begin'#010+
+  '  Result:=Count-1;'#010+
+  '  While (Result>=0) and (CompareText(GetNamedItem(Result).Name,AName)<'+
+  '>0) do'#010+
+  '    Dec(Result);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TNam','edItemList.ItemByName(const ANAme: String): TNamedItem;'+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  I:=IndexOfName(AName);'#010+
+  '  If (I=-1) Then'#010+
+  '    Raise ECollectionError.CreateFmt(SErrNoSuchName,[AName]);'#010+
+  '  Result:=TNamedItem(Items[i]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{***************','****************************************************'+
+  '*********'#010+
+  '                                TTargets'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'function TTargets.GetTargetItem(Index : Integer): TTarget;',#010+
+  'begin'#010+
+  '  Result:=TTarget(Items[Index]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTargets.GetTarget(const AName : String): TTarget;'#010+
+  'begin'#010+
+  '  Result:=TTarget(ItemByName(AName));'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TTargets.SetTargetItem(Index : Integer; const AValue: TTarge'+
+  't);'#010+
+  'begin'#010+
+  '  ','Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddUnit(Const AUnitName : String) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddUnit(AUnitName,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddUnit(Const AUnitName : String;const OSes:TOSes) :'+
+  ' TTarget;'#010+
+  'begin'#010+
+  '  R','esult:=AddUnit(AUnitName,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddUnit(Const AUnitName : String;const CPUs:TCPUs) :'+
+  ' TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddUnit(AUnitName,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddUnit(Const AUnitName : String;const ','CPUs:TCPUs;'+
+  'const OSes:TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=Add as TTarget;'#010+
+  '  Result.Name:=AUnitName;'#010+
+  '  Result.TargetType:=TTUnit;'#010+
+  '  Result.CPUs:=CPUs;'#010+
+  '  Result.OSes:=OSes;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddImplicitUnit(Const AUnitName : String;Insta','llUn'+
+  'it:boolean=true) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddImplicitUnit(AUnitName,AllCPUs,AllOSes,InstallUnit);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddImplicitUnit(Const AUnitName : String;const OSes:'+
+  'TOSes;InstallUnit:boolean=true) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=','AddImplicitUnit(AUnitName,AllCPUs,OSes,InstallUnit);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddImplicitUnit(Const AUnitName : String;const CPUs:'+
+  'TCPUs;InstallUnit:boolean=true) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddImplicitUnit(AUnitName,CPUs,AllOSes,InstallUnit)',';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddImplicitUnit(Const AUnitName : String;const CPUs:'+
+  'TCPUs;const OSes:TOSes;InstallUnit:boolean=true) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=Add as TTarget;'#010+
+  '  Result.Name:=AUnitName;'#010+
+  '  Result.CPUs:=CPUs;'#010+
+  '  Result.OSes:=OSes;'#010+
+  ' ',' if InstallUnit then'#010+
+  '    Result.TargetType:=TTImplicitUnit'#010+
+  '  else'#010+
+  '    Result.TargetType:=TTCleanOnlyUnit;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddProgram(Const AProgramName : String) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddProgram(AProgramName,AllCPUs,AllOSes);'#010,
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddProgram(Const AProgramName : String;const OSes:TO'+
+  'Ses) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddProgram(AProgramName,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddProgram(Const AProgramName : String;const CPUs:TC'+
+  'PUs) : TTarget;',#010+
+  'begin'#010+
+  '  Result:=AddProgram(AProgramName,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddProgram(Const AProgramName : String;const CPUs:TC'+
+  'PUs;const OSes:TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=Add as TTarget;'#010+
+  '  Result.Name:=AProgramName;'#010+
+  '  Result.CPUs',':=CPUs;'#010+
+  '  Result.OSes:=OSes;'#010+
+  '  Result.TargetType:=ttProgram;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleUnit(Const AUnitName : String) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleUnit(AUnitName,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleUnit(Con','st AUnitName : String;const OSes'+
+  ':TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleUnit(AUnitName,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleUnit(Const AUnitName : String;const CPUs:T'+
+  'CPUs) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleUnit(AUnitNam','e,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleUnit(Const AUnitName : String;const CPUs:T'+
+  'CPUs;const OSes:TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=Add as TTarget;'#010+
+  '  Result.Name:=AUnitName;'#010+
+  '  Result.CPUs:=CPUs;'#010+
+  '  Result.OSes:=OSes;'#010+
+  '  Result.Tar','getType:=ttExampleUnit;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleProgram(Const AProgramName : String) : TTa'+
+  'rget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleProgram(AProgramName,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleProgram(Const AProgramName : Stri','ng;cons'+
+  't OSes:TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleProgram(AProgramName,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleProgram(Const AProgramName : String;const '+
+  'CPUs:TCPUs) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=AddExampleProgram(AProgramName',',CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TTargets.AddExampleProgram(Const AProgramName : String;const '+
+  'CPUs:TCPUs;const OSes:TOSes) : TTarget;'#010+
+  'begin'#010+
+  '  Result:=Add as TTarget;'#010+
+  '  Result.Name:=AProgramName;'#010+
+  '  Result.CPUs:=CPUs;'#010+
+  '  Result.OSes:=OSes;'#010+
+  '  Re','sult.TargetType:=ttExampleProgram;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                                TSources'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010,
+  'function TSources.GetSourceItem(Index : Integer): TSource;'#010+
+  'begin'#010+
+  '  Result:=TSource(Items[Index]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TSources.SetSourceItem(Index : Integer; const AValue: TSourc'+
+  'e);'#010+
+  'begin'#010+
+  '  Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TSources.AddDoc',' (const AFiles : String) : TSource;'#010+
+  'begin'#010+
+  '  Result:=Add as TSource;'#010+
+  '  Result.Name:=AFiles;'#010+
+  '  Result.FSourceType:=stDoc;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TSources.AddSrc(const AFiles : String) : TSource;'#010+
+  'begin'#010+
+  '  Result:=Add as TSource;'#010+
+  '  Result.Name:=AFiles;',#010+
+  '  Result.FSourceType:=stSrc;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TSources.AddExample(const AFiles : String) : TSource;'#010+
+  'begin'#010+
+  '  Result:=Add as TSource;'#010+
+  '  Result.Name:=AFiles;'#010+
+  '  Result.FSourceType:=stExample;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TSources.AddTest(const AFiles : Stri','ng) : TSource;'#010+
+  'begin'#010+
+  '  Result:=Add as TSource;'#010+
+  '  Result.Name:=AFiles;'#010+
+  '  Result.FSourceType:=stTest;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TSources.AddDocFiles(const AFileMask: string; Recursive: boo'+
+  'lean);'#010+
+  'var'#010+
+  '  List : TStrings;'#010+
+  '  i: integer;'#010+
+  'begin'#010+
+  '  List := TSt','ringList.Create;'#010+
+  '  SearchFiles(AFileMask, Recursive, List);'#010+
+  '  for i:= 0 to Pred(List.Count) do'#010+
+  '    AddDoc(List[i]);'#010+
+  '  List.Free;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TSources.AddSrcFiles(const AFileMask: string; Recursive: boo'+
+  'lean);'#010+
+  'var'#010+
+  '  List : TStrings;'#010+
+  '  i:',' integer;'#010+
+  'begin'#010+
+  '  List := TStringList.Create;'#010+
+  '  SearchFiles(AFileMask, Recursive, List);'#010+
+  '  for i:= 0 to Pred(List.Count) do'#010+
+  '    AddSrc(List[i]);'#010+
+  '  List.Free;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TSources.AddExampleFiles(const AFileMask: string; Recursive:'+
+  ' bool','ean);'#010+
+  'var'#010+
+  '  List : TStrings;'#010+
+  '  i: integer;'#010+
+  'begin'#010+
+  '  List := TStringList.Create;'#010+
+  '  SearchFiles(AFileMask, Recursive, List);'#010+
+  '  for i:= 0 to Pred(List.Count) do'#010+
+  '    AddExample(List[i]);'#010+
+  '  List.Free;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TSources.AddTestFiles(const ','AFileMask: string; Recursive: '+
+  'boolean);'#010+
+  'var'#010+
+  '  List : TStrings;'#010+
+  '  i: integer;'#010+
+  'begin'#010+
+  '  List := TStringList.Create;'#010+
+  '  SearchFiles(AFileMask, Recursive, List);'#010+
+  '  for i:= 0 to Pred(List.Count) do'#010+
+  '    AddTest(List[i]);'#010+
+  '  List.Free;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{******','*************************************************************'+
+  '*********'#010+
+  '                             TPackage'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'constructor TPackage.Create(ACollection: TCollection',');'#010+
+  'begin'#010+
+  '  inherited Create(ACollection);'#010+
+  '  FTargets:=TTargets.Create(TTarget);'#010+
+  '  FSources:=TSources.Create(TSource);'#010+
+  '  FDependencies:=TDependencies.Create(TDependency);'#010+
+  '  FInstallFiles:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FCl','eanFiles:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FArchiveFiles:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FUnitPath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FObjectPath:=TConditionalStrings.Create(TConditionalSt','ring);'#010+
+  '  FIncludePath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FSourcePath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FExamplePath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FTestPath:=TConditionalStrings.Create(TC','onditionalString);'#010+
+  '  FCommands:=TCommands.Create(TCommand);'#010+
+  '  FCPUs:=AllCPUs;'#010+
+  '  FOSes:=AllOSes;'#010+
+  '  // Implicit dependency on RTL'#010+
+  '  FDependencies.Add('#039'rtl'#039');'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TPackage.destroy;'#010+
+  'begin'#010+
+  '  FreeAndNil(FDependencies);'#010+
+  '  FreeAndNil(','FInstallFiles);'#010+
+  '  FreeAndNil(FCleanFiles);'#010+
+  '  FreeAndNil(FArchiveFiles);'#010+
+  '  FreeAndNil(FIncludePath);'#010+
+  '  FreeAndNil(FSourcePath);'#010+
+  '  FreeAndNil(FExamplePath);'#010+
+  '  FreeAndNil(FTestPath);'#010+
+  '  FreeAndNil(FObjectPath);'#010+
+  '  FreeAndNil(FUnitPath);'#010+
+  '  FreeAn','dNil(FSources);'#010+
+  '  FreeAndNil(FTargets);'#010+
+  '  inherited destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.SetName(const AValue: String);'#010+
+  'begin'#010+
+  '  inherited SetName(AValue);'#010+
+  '  // RTL should not have any dependencies'#010+
+  '  if AValue='#039'rtl'#039' then'#010+
+  '    FDependencies.Clea','r;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure TPackage.GetManifest(Manifest : TStrings);'#010+
+  'Var'#010+
+  '  S : String;'#010+
+  '  Release,Minor,Major : Word;'#010+
+  '  i : Integer;'#010+
+  '  D : TConditionalString;'#010+
+  'begin'#010+
+  '  With Manifest do'#010+
+  '    begin'#010+
+  '    Add(Format('#039'<package name="%s">'#039',[QuoteXml(Name)]','));'#010+
+  '    SplitVersion(Version,Release,Minor,Major,S);'#010+
+  '    Add(Format('#039'<version release="%d" major="%d" minor="%d" suffix'+
+  '="%s"/>'#039',[Release,Minor,Major,QuoteXMl(S)]));'#010+
+  '    Add(Format('#039'<filename>%s</filename>'#039',[QuoteXml(FileName + '+
+  'ZipExt)]));'#010+
+  ' ','   Add(Format('#039'<author>%s</author>'#039',[QuoteXml(Author)]));'#010+
+  '    Add(Format('#039'<license>%s</license>'#039',[QuoteXml(License)]));'#010+
+  '    if ExternalURL<>'#039#039' then'#010+
+  '      Add(Format('#039'<externalurl>%s</externalurl>'#039',[QuoteXml(Ext'+
+  'ernalURL)]));'#010+
+  '    Add(Format('#039,'<email>%s</email>'#039',[QuoteXMl(Email)]));'#010+
+  '    S:=Description;'#010+
+  '    If (S<>'#039#039') then'#010+
+  '      Add(Format('#039'<description>%s</description>'#039',[QuoteXML(S)]'+
+  '));'#010+
+  '    If (Dependencies.Count>0) then'#010+
+  '      begin'#010+
+  '        Add('#039'<dependencies>'#039');'#010+
+  '        for I:=0',' to Dependencies.Count-1 do'#010+
+  '          begin'#010+
+  '            D:=Dependencies[i];'#010+
+  '            S:='#039#039';'#010+
+  '            if (D.OSes<>AllOSes) then'#010+
+  '              S:=S+'#039' os="'#039'+OSesToString(D.OSes)+'#039'"'#039';'#010+
+  '            if (D.CPUs<>AllCPUs) then'#010+
+  '              S:','=S+'#039' cpu="'#039'+CPUsToString(D.CPUs)+'#039'"'#039';'+
+  #010+
+  '            Add(Format('#039'<dependency><package%s packagename="%s"/><'+
+  '/dependency>'#039',[S,QuoteXML(D.Value)]));'#010+
+  '          end;'#010+
+  '        Add('#039'</dependencies>'#039');'#010+
+  '      end;'#010+
+  '    Add('#039'</package>'#039');'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010,
+  'procedure TPackage.GetCleanFiles(List: TStrings; Const APrefixU, APref'+
+  'ixB : String; ACPU:TCPU; AOS : TOS);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  AddConditionalStrings(List,CleanFiles,ACPU,AOS,APrefixU);'#010+
+  '  For I:=0 to FTargets.Count-1 do'#010+
+  '    FTargets.T','argetItems[I].GetCleanFiles(List, APrefixU, APrefixB, '+
+  'ACPU, AOS);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.GetInstallFiles(List: TStrings;Types : TTargetTypes'+
+  ';Const APrefix, APrefixU, APrefixB: String; ACPU:TCPU; AOS : TOS);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  T : TTarg','et;'#010+
+  'begin'#010+
+  '  AddConditionalStrings(List,InstallFiles,ACPU,AOS,APrefix);'#010+
+  '  For I:=0 to FTargets.Count-1 do'#010+
+  '    begin'#010+
+  '      T:=FTargets.TargetItems[I];'#010+
+  '      if (T.TargetType in Types)  then'#010+
+  '        T.GetInstallFiles(List, APrefixU, APrefixB, ','ACPU, AOS);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.GetArchiveFiles(List: TStrings; ACPU:TCPU; AOS : TO'+
+  'S);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  // Targets only'#010+
+  '  For I:=0 to FTargets.Count-1 do'#010+
+  '    FTargets.TargetItems[I].GetArchiveFiles(List,ACPU,AOS);'#010+
+  ' ',' // Additional archive files'#010+
+  '  AddConditionalStrings(List,ArchiveFiles,ACPU,AOS);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TPackage.GetDescription : string;'#010+
+  'Var'#010+
+  '  FN : String;'#010+
+  '  L : TStringList;'#010+
+  'begin'#010+
+  '  If (FDescription<>'#039#039') then'#010+
+  '    Result:=FDescription'#010+
+  '  else'#010+
+  '   ',' If (FDescriptionFile<>'#039#039') then'#010+
+  '      begin'#010+
+  '        // Always relative to binary name.'#010+
+  '        FN:=ExtractFilePath(ParamStr(0));'#010+
+  '        FN:=FN+FDescriptionFile;'#010+
+  '        If FileExists(FN) then'#010+
+  '          begin'#010+
+  '            L:=TStringList.Crea','te;'#010+
+  '            Try'#010+
+  '              L.LoadFromFile(FN);'#010+
+  '              Result:=L.Text;'#010+
+  '            Finally'#010+
+  '              L.Free;'#010+
+  '            end;'#010+
+  '          end;'#010+
+  '      end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TPackage.GetFileName : string;'#010+
+  'begin'#010+
+  '  If (FFileName<>'#039,#039') then'#010+
+  '    Result:=FFileName'#010+
+  '  else'#010+
+  '    if Version <> '#039#039' then'#010+
+  '      Result := Name + '#039'-'#039' + Version'#010+
+  '    else'#010+
+  '      Result := Name;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.LoadUnitConfigFromFile(Const AFileName: String);'#010+
+  'Var'#010+
+  '  F : TFileStream;'#010+
+  'begin'#010+
+  '  F:=','TFileStream.Create(AFileName,fmOpenRead);'#010+
+  '  Try'#010+
+  '    LoadUnitConfigFromStream(F);'#010+
+  '  Finally'#010+
+  '    F.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.SaveUnitConfigToFile(Const AFileName: String;ACPU:T'+
+  'CPU;AOS:TOS);'#010+
+  'Var'#010+
+  '  F : TFileStream;'#010+
+  'begin'#010+
+  '  F:=TFile','Stream.Create(AFileName,fmCreate);'#010+
+  '  Try'#010+
+  '    SaveUnitConfigToStream(F,ACPU,AOS);'#010+
+  '  Finally'#010+
+  '    F.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.SaveUnitConfigToStream(S : TStream;ACPU:TCPU;AOS:TO'+
+  'S);'#010+
+  'Var'#010+
+  '  L : TStringList;'#010+
+  '  Deps : String;'#010+
+  '  i : int','eger;'#010+
+  '  D : TDependency;'#010+
+  'begin'#010+
+  '  L:=TStringList.Create;'#010+
+  '  try'#010+
+  '    With L do'#010+
+  '      begin'#010+
+  '        Values[KeyName]:=Name;'#010+
+  '        Values[KeyVersion]:=Version;'#010+
+  '        Values[KeyCPU]:=CPUToString(ACPU);'#010+
+  '        Values[KeyOS]:=OSToString(AOS);'#010+
+  ' ','       Deps:='#039#039';'#010+
+  '        for i:=0 to Dependencies.Count-1 do'#010+
+  '          begin'#010+
+  '            D:=Dependencies[i];'#010+
+  '            if (ACPU in D.CPUs) and (AOS in D.OSes) then'#010+
+  '              begin'#010+
+  '                if Deps='#039#039' then'#010+
+  '                  Deps',':=D.Value'#010+
+  '                else'#010+
+  '                  Deps:=Deps+'#039','#039'+D.Value;'#010+
+  '              end;'#010+
+  '          end;'#010+
+  '        Values[KeyDepends]:=Deps;'#010+
+  '        if NeedLibC then'#010+
+  '          Values[KeyNeedLibC]:='#039'Y'#039#010+
+  '        else'#010+
+  '          Values[KeyNeedLi','bC]:='#039'N'#039';'#010+
+  '      end;'#010+
+  '    L.SaveToStream(S);'#010+
+  '  Finally'#010+
+  '    L.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackage.LoadUnitConfigFromStream(S: TStream);'#010+
+  'Var'#010+
+  '  L,L2 : TStrings;'#010+
+  '  Line : String;'#010+
+  '  I,P,PC : Integer;'#010+
+  '  VOS : TOS;'#010+
+  '  VCPU : TCPU;'#010+
+  'begin'#010+
+  '  L:=TStr','ingList.Create;'#010+
+  '  Try'#010+
+  '    L.LoadFromStream(S);'#010+
+  '    // Fix lines.'#010+
+  '    For I:=L.Count-1 downto 0 do'#010+
+  '      begin'#010+
+  '        Line:=L[I];'#010+
+  '        P:=Pos('#039'='#039',Line);'#010+
+  '        PC:=Pos('#039';'#039',Line);  // Comment line.'#010+
+  '        If (P=0) or ((PC<>0) and (PC<P)',') then'#010+
+  '          L.Delete(I)'#010+
+  '        else'#010+
+  '          L[i]:=Trim(System.Copy(Line,1,P-1)+'#039'='#039'+Trim(System.C'+
+  'opy(Line,P+1,Length(Line)-P)));'#010+
+  '      end;'#010+
+  '    With L do'#010+
+  '      begin'#010+
+  '        Version:=Values[KeyVersion];'#010+
+  '        VCPU:=StringToCPU(Valu','es[KeyCPU]);'#010+
+  '        VOS:=StringToOS(Values[KeyOS]);'#010+
+  '        OSes:=[VOS];'#010+
+  '        CPUs:=[VCPU];'#010+
+  '        L2:=TStringList.Create;'#010+
+  '        L2.CommaText:=Values[KeyDepends];'#010+
+  '        for i:=0 to L2.Count-1 do'#010+
+  '          Dependencies.Add(L2[i],CPU','s,OSes);'#010+
+  '        FreeAndNil(L2);'#010+
+  '        NeedLibC:=Upcase(Values[KeyNeedLibC])='#039'Y'#039';'#010+
+  '      end;'#010+
+  '  Finally'#010+
+  '    L.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                              T','Packages'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'function TPackages.GetPackage(const AName : String): TPackage;'#010+
+  'begin'#010+
+  '  Result:=TPackage(ItemByName(AName))'#010+
+  'end;'#010+
+  #010+
+  'function TPackages.GetPackageItem(AInde','x : Integer): TPackage;'#010+
+  'begin'#010+
+  '  Result:=TPackage(Items[AIndex]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TPackages.SetPackageItem(AIndex : Integer; const AValue: TPa'+
+  'ckage);'#010+
+  'begin'#010+
+  '  Items[AIndex]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TPackages.AddPackage(const AName: String): ','TPackage;'#010+
+  'begin'#010+
+  '  Result:=Add as TPackage;'#010+
+  '  Result.Name:=AName;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                             TCustomDefaults'#010+
+  '*********************************************','***********************'+
+  '********}'#010+
+  #010+
+  'procedure TCustomDefaults.SetCPU(const AValue: TCPU);'#010+
+  'begin'#010+
+  '  FCPU:=AValue;'#010+
+  '  RecalcTarget;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetBaseInstallDir: String;'#010+
+  'begin'#010+
+  '  If (FBaseInstallDir<>'#039#039') then'#010+
+  '    Result:=FBase','InstallDir'#010+
+  '  else'#010+
+  '    if UnixPaths then'#010+
+  '      Result:=Prefix +'#039'lib'#039' + PathDelim + '#039'fpc'#039' + Path'+
+  'Delim'#010+
+  '    else'#010+
+  '      Result:=Prefix;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetBinInstallDir: String;'#010+
+  'begin'#010+
+  '  If (FBinInstallDir<>'#039#039') then'#010+
+  '    Result:=FB','inInstallDir'#010+
+  '  else'#010+
+  '    If UnixPaths then'#010+
+  '      Result:=BaseInstallDir+'#039'bin'#039#010+
+  '    else'#010+
+  '      Result:=BaseInstallDir+'#039'bin'#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetCompiler: String;'#010+
+  'begin'#010+
+  '  If (FCompiler<>'#039#039') then'#010+
+  '    Result:=FCompiler'#010+
+  '  else'#010+
+  '    ','Result:='#039'fpc'#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetDocInstallDir: String;'#010+
+  'begin'#010+
+  '  If (FBinInstallDir<>'#039#039') then'#010+
+  '    Result:=FBinInstallDir'#010+
+  '  else'#010+
+  '    If UnixPaths then'#010+
+  '      Result:=Prefix+'#039'share'#039'+PathDelim+'#039'doc'#039#010+
+  '    else'#010+
+  '      Result:=BaseIn','stallDir+'#039'docs'#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetExamplesInstallDir: String;'#010+
+  'begin'#010+
+  '  If (FExamplesInstallDir<>'#039#039') then'#010+
+  '    Result:=FExamplesInstallDir'#010+
+  '  else'#010+
+  '    If UnixPaths then'#010+
+  '      Result:=Prefix+'#039'share'#039'+PathDelim+'#039'docs'#039'+PathDeli'+
+  'm+'#039,'examples'#039#010+
+  '    else'#010+
+  '      Result:=BaseInstallDir+'#039'examples'#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetUnitInstallDir: String;'#010+
+  'begin'#010+
+  '  If (FUnitInstallDir<>'#039#039') then'#010+
+  '    Result:=FUnitInstallDir'#010+
+  '  else'#010+
+  '    If UnixPaths then'#010+
+  '      Result:=BaseInstallD','ir+'#039'units'#039'+PathDelim+Target'#010+
+  '    else'#010+
+  '      Result:=BaseInstallDir+'#039'units'#039'+PathDelim+Target;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetLocalUnitDir: String;'#010+
+  'begin'#010+
+  '  Result:=FLocalUnitDir;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCustomDefaults.GetGlobalUnitDir: String;'#010+
+  'be','gin'#010+
+  '  If (FGlobalUnitDir<>'#039#039') then'#010+
+  '    Result:=FGlobalUnitDir'#010+
+  '  else'#010+
+  '    Result:=UnitInstallDir;'#010+
+  'end;'#010+
+  #010+
+  'procedure TCustomDefaults.SetLocalUnitDir(const AValue: String);'#010+
+  'begin'#010+
+  '  // Use ExpandFileName to support ~/ expansion'#010+
+  '  if AValue<>'#039#039' th','en'#010+
+  '    FLocalUnitDir:=IncludeTrailingPathDelimiter(ExpandFileName(AValue)'+
+  ')'#010+
+  '  else'#010+
+  '    FLocalUnitDir:='#039#039';'#010+
+  'end;'#010+
+  #010+
+  'procedure TCustomDefaults.SetGlobalUnitDir(const AValue: String);'#010+
+  'begin'#010+
+  '  // Use ExpandFileName to support ~/ expansion'#010+
+  '  if AVal','ue<>'#039#039' then'#010+
+  '    FGlobalUnitDir:=IncludeTrailingPathDelimiter(ExpandFileName(AValue'+
+  '))'#010+
+  '  else'#010+
+  '    FGlobalUnitDir:='#039#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.SetBaseInstallDir(const AValue: String);'#010+
+  'begin'#010+
+  '  // Use ExpandFileName to support ~/ expans','ion'#010+
+  '  if AValue<>'#039#039' then'#010+
+  '    FBaseInstallDir:=IncludeTrailingPathDelimiter(ExpandFileName(AValu'+
+  'e))'#010+
+  '  else'#010+
+  '    FBaseInstallDir:='#039#039';'#010+
+  '  UnitInstallDir:='#039#039';'#010+
+  '  BinInstallDir:='#039#039';'#010+
+  '  ExamplesInstallDir:='#039#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.SetOS(c','onst AValue: TOS);'#010+
+  'begin'#010+
+  '  FOS:=AValue;'#010+
+  '  Recalctarget;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.SetPrefix(const AValue: String);'#010+
+  'begin'#010+
+  '  if FPrefix=AValue then exit;'#010+
+  '  FPrefix:=IncludeTrailingPathDelimiter(AValue);'#010+
+  '  BaseInstallDir:='#039#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'pro','cedure TCustomDefaults.SetTarget(const AValue: String);'#010+
+  'Var'#010+
+  '  P : Integer;'#010+
+  'begin'#010+
+  '  if FTarget<>AValue then'#010+
+  '    begin'#010+
+  '      P:=Pos('#039'-'#039',AValue);'#010+
+  '      If (P<>0) then'#010+
+  '        begin'#010+
+  '          FOS:=StringToOS(System.Copy(Avalue,P+1,Length(AValue',')-P));'+
+  #010+
+  '          FCPU:=StringToCPU(System.Copy(Avalue,1,P-1));'#010+
+  '        end'#010+
+  '      else'#010+
+  '        FOS:=StringToOS(AValue);'#010+
+  '      FTarget:=AValue;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.RecalcTarget;'#010+
+  'begin'#010+
+  '  Ftarget:=CPUToString(FCPU)+'#039'-'#039'+OSt','oString(FOS);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'constructor TCustomDefaults.Create;'#010+
+  'begin'#010+
+  '  InitDefaults;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.InitDefaults;'#010+
+  'begin'#010+
+  '  {$ifdef unix}'#010+
+  '  UnixPaths:=True;'#010+
+  '  {$else}'#010+
+  '  UnixPaths:=False;'#010+
+  '  {$endif}'#010+
+  '  FSourceExt:=PPExt;'#010+
+  '  FNoFPCCfg',':=False;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.Assign(ASource: TPersistent);'#010+
+  'Var'#010+
+  '  d : TCustomDefaults;'#010+
+  'begin'#010+
+  '  If ASource is TCustomDefaults then'#010+
+  '    begin'#010+
+  '      D:=ASource as TCustomDefaults;'#010+
+  '      FArchive:=D.Farchive;'#010+
+  '      FCompiler:=D.Comp','iler;'#010+
+  '      FCopy:=D.FCopy;'#010+
+  '      FCPU:=D.FCPU;'#010+
+  '      FMode:=D.FMode;'#010+
+  '      FMkDir:=D.FMkDir;'#010+
+  '      FMove:=D.FMove;'#010+
+  '      FOptions:=D.FOptions;'#010+
+  '      FOS:=D.FOS;'#010+
+  '      FLocalUnitDir:=D.FLocalUnitDir;'#010+
+  '      FGlobalUnitDir:=D.FGlobalUnitDir;'#010,
+  '      FPrefix:=D.FPrefix;'#010+
+  '      FBaseInstallDir:=D.FBaseInstallDir;'#010+
+  '      FUnitInstallDir:=D.FUnitInstallDir;'#010+
+  '      FBinInstallDir:=D.FBinInstallDir;'#010+
+  '      FDocInstallDir:=D.FDocInstallDir;'#010+
+  '      FExamplesInstallDir:=D.FExamplesInstallDir;'#010,
+  '      FRemove:=D.FRemove;'#010+
+  '      FTarget:=D.FTarget;'#010+
+  '      FUnixPaths:=D.FUnixPaths;'#010+
+  '      FSourceExt:=D.SourceExt;'#010+
+  '    end'#010+
+  '  else'#010+
+  '    Inherited;'#010+
+  'end;'#010+
+  #010+
+  'procedure TCustomDefaults.LocalInit(Const AFileName : String);'#010+
+  #010+
+  'Var'#010+
+  '  FN : String;'#010+
+  #010+
+  'begin',#010+
+  '  FN:=AFileName;'#010+
+  '  If (FN='#039#039') then'#010+
+  '    begin'#010+
+  '    // Environment variable.'#010+
+  '    FN:=GetEnvironmentVariable('#039'FPMAKECFG'#039');'#010+
+  '    If (FN<>'#039#039') then'#010+
+  '      If not FileExists(FN) then'#010+
+  '        FN:='#039#039';'#010+
+  '    // User config file fpmake.cfg'#010+
+  '    If (FN='#039#039') ','then'#010+
+  '      begin'#010+
+  '      FN:=GetAppConfigFile(False);'#010+
+  '      If Not FileExists(FN) then'#010+
+  '        FN:='#039#039';'#010+
+  '      end;'#010+
+  '    // Global config file fpmake.cfg'#010+
+  '    If (FN='#039#039') then'#010+
+  '      begin'#010+
+  '      FN:=GetAppConfigFile(True);'#010+
+  '      If Not FileExists(F','N) then'#010+
+  '        FN:='#039#039';'#010+
+  '      end;'#010+
+  '    end;'#010+
+  '  If (FN<>'#039#039') and FileExists(FN) then'#010+
+  '    LoadFromFile(FN);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.CompilerDefaults;'#010+
+  '{$ifdef HAS_UNIT_PROCESS}'#010+
+  'var'#010+
+  '  infoSL : TStringList;'#010+
+  '{$endif HAS_UNIT_PROCESS}'#010+
+  'begin',#010+
+  '{$ifdef HAS_UNIT_PROCESS}'#010+
+  '  // Detect compiler version/target from -i option'#010+
+  '  infosl:=TStringList.Create;'#010+
+  '  infosl.Delimiter:='#039' '#039';'#010+
+  '  infosl.DelimitedText:=GetCompilerInfo(GetCompiler,'#039'-iVTPTO'#039')'+
+  ';'#010+
+  '  if infosl.Count<>3 then'#010+
+  '    Raise EInstal','lerError.Create(SErrInvalidFPCInfo);'#010+
+  '  FCompilerVersion:=infosl[0];'#010+
+  '  CPU:=StringToCPU(infosl[1]);'#010+
+  '  OS:=StringToOS(infosl[2]);'#010+
+  '{$else HAS_UNIT_PROCESS}'#010+
+  '  if CPU=cpuNone then'#010+
+  '    CPU:=StringToCPU({$I %FPCTARGETCPU%});'#010+
+  '  if OS=osNone then'#010+
+  '  ','  OS:=StringToOS({$I %FPCTARGETOS%});'#010+
+  '  if FCompilerVersion='#039#039' then'#010+
+  '    FCompilerVersion:={$I %FPCVERSION%};'#010+
+  '{$endif HAS_UNIT_PROCESS}'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.LoadFromFile(Const AFileName: String);'#010+
+  'Var'#010+
+  '  F : TFileStream;'#010+
+  'begin'#010+
+  '  F:','=TFileStream.Create(AFileName,fmOpenRead);'#010+
+  '  Try'#010+
+  '    LoadFromStream(F);'#010+
+  '  Finally'#010+
+  '    F.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.SaveToFile(Const AFileName: String);'#010+
+  'Var'#010+
+  '  F : TFileStream;'#010+
+  'begin'#010+
+  '  F:=TFileStream.Create(AFileName,fmCrea','te);'#010+
+  '  Try'#010+
+  '    SaveToStream(F);'#010+
+  '  Finally'#010+
+  '    F.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.SaveToStream(S : TStream);'#010+
+  'Var'#010+
+  '  L : TStringList;'#010+
+  'begin'#010+
+  '  L:=TStringList.Create;'#010+
+  '  try'#010+
+  '    With L do'#010+
+  '      begin'#010+
+  '      Values[KeyArchive]:=FArchiv','e;'#010+
+  '      Values[KeyCompiler]:=FCompiler;'#010+
+  '      Values[KeyCopy]:=FCopy;'#010+
+  '      Values[KeyMkDir]:=FMkDir;'#010+
+  '      Values[KeyMove]:=FMove;'#010+
+  '      Values[KeyOptions]:=FOptions;'#010+
+  '      Values[KeyCPU]:=CPUToString(FCPU);'#010+
+  '      Values[KeyOS]:=OSToStrin','g(FOS);'#010+
+  '      Values[KeyMode]:=ModeToString(FMode);'#010+
+  '      Values[KeyLocalUnitDir]:=FLocalUnitDir;'#010+
+  '      Values[KeyGlobalUnitDir]:=FGlobalUnitDir;'#010+
+  '      Values[KeyPrefix]:=FPrefix;'#010+
+  '      Values[KeyBaseInstallDir]:=FBaseInstallDir;'#010+
+  '      Valu','es[KeyUnitInstallDir]:=FUnitInstallDir;'#010+
+  '      Values[KeyBinInstallDir]:=FBinInstallDir;'#010+
+  '      Values[KeyDocInstallDir]:=FDocInstallDir;'#010+
+  '      Values[KeyExamplesInstallDir]:=FExamplesInstallDir;'#010+
+  '      Values[KeyRemove]:=FRemove;'#010+
+  '      Values','[KeyTarget]:=FTarget;'#010+
+  '      Values[KeySourceExt]:=FSourceExt;'#010+
+  '      if FNoFPCCfg then'#010+
+  '        Values[KeyNoFPCCfg]:='#039'Y'#039';'#010+
+  '      end;'#010+
+  '    L.SaveToStream(S);'#010+
+  '  Finally'#010+
+  '    L.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomDefaults.LoadFromStream(S: TStrea','m);'#010+
+  'Var'#010+
+  '  L : TStrings;'#010+
+  '  Line : String;'#010+
+  '  I,P,PC : Integer;'#010+
+  'begin'#010+
+  '  L:=TStringList.Create;'#010+
+  '  Try'#010+
+  '    L.LoadFromStream(S);'#010+
+  '    // Fix lines.'#010+
+  '    For I:=L.Count-1 downto 0 do'#010+
+  '      begin'#010+
+  '      Line:=L[I];'#010+
+  '      P:=Pos('#039'='#039',Line);'#010+
+  '      PC:=Po','s('#039';'#039',Line);  // Comment line.'#010+
+  '      If (P=0) or ((PC<>0) and (PC<P)) then'#010+
+  '        L.Delete(I)'#010+
+  '      else'#010+
+  '        L[i]:=Trim(System.Copy(Line,1,P-1)+'#039'='#039'+Trim(System.Cop'+
+  'y(Line,P+1,Length(Line)-P)));'#010+
+  '      end;'#010+
+  '    With L do'#010+
+  '      begin'#010+
+  '     ',' FArchive:=Values[KeyArchive];'#010+
+  '      FCompiler:=Values[KeyCompiler];'#010+
+  '      FCopy:=Values[KeyCopy];'#010+
+  '      FMkDir:=Values[KeyMkDir];'#010+
+  '      FMove:=Values[KeyMove];'#010+
+  '      FRemove:=Values[KeyRemove];'#010+
+  '      FOptions:=Values[KeyOptions];'#010+
+  '      Lin','e:=Values[KeyCPU];'#010+
+  '      If (Line<>'#039#039') then'#010+
+  '        FCPU:=StringToCPU(Line);'#010+
+  '      Line:=Values[KeyOS];'#010+
+  '      If (Line<>'#039#039') then'#010+
+  '        FOS:=StringToOS(Line);'#010+
+  '      Line:=Values[KeyMode];'#010+
+  '      If (Line<>'#039#039') then'#010+
+  '        FMode:=StringToMod','e(Line);'#010+
+  '      FTarget:=Values[KeyTarget];'#010+
+  '      FLocalUnitDir:=Values[KeyLocalUnitDir];'#010+
+  '      FGlobalUnitDir:=Values[KeyGlobalUnitDir];'#010+
+  '      FPrefix:=Values[KeyPrefix];'#010+
+  '      FBaseInstallDir:=Values[KeyBaseInstallDir];'#010+
+  '      FUnitInstallD','ir:=Values[KeyUnitInstallDir];'#010+
+  '      FBinInstallDir:=Values[KeyBinInstallDir];'#010+
+  '      FDocInstallDir:=Values[KeyDocInstallDir];'#010+
+  '      FExamplesInstallDir:=Values[KeyExamplesInstallDir];'#010+
+  '      FSourceExt:=Values[KeySourceExt];'#010+
+  '      If (FSour','ceExt='#039#039') then'#010+
+  '        FSourceExt:=PPExt;'#010+
+  '      FNoFPCCfg:=(Upcase(Values[KeyNoFPCCfg])='#039'Y'#039');'#010+
+  '      end;'#010+
+  '  Finally'#010+
+  '    L.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                     ','        TFPCDefaults'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'procedure TFPCDefaults.CompilerDefaults;'#010+
+  'var'#010+
+  '  BD : String;'#010+
+  'begin'#010+
+  '  inherited CompilerDefaults;'#010+
+  #010+
+  '  // Use the same algorithm as the compiler',', see options.pas'#010+
+  '{$ifdef Unix}'#010+
+  '  BD:=FixPath(GetEnvironmentVariable('#039'FPCDIR'#039'));'#010+
+  '  if BD='#039#039' then'#010+
+  '    begin'#010+
+  '      BD:='#039'/usr/local/lib/fpc/'#039'+FCompilerVersion;'#010+
+  '      if not DirectoryExists(BD) and'#010+
+  '         DirectoryExists('#039'/usr/lib/fpc/'#039'+FComp','ilerVersion) t'+
+  'hen'#010+
+  '        BD:='#039'/usr/lib/fpc/'#039'+FCompilerVersion;'#010+
+  '    end;'#010+
+  '{$else unix}'#010+
+  '  BD:=FixPath(GetEnvironmentVariable('#039'FPCDIR'#039'));'#010+
+  '  if BD='#039#039' then'#010+
+  '    begin'#010+
+  '      BD:=ExtractFilePath(FCompiler)+'#039'..'#039';'#010+
+  '      if not(DirectoryExists(BD+'#039'/un','its'#039')) and'#010+
+  '         not(DirectoryExists(BD+'#039'/rtl'#039')) then'#010+
+  '        BD:=FBaseInstallDir+'#039'..'#039';'#010+
+  '    end;'#010+
+  '{$endif unix}'#010+
+  #010+
+  '  // Where to install by default'#010+
+  '  if (FBaseInstallDir='#039#039') and (FPrefix='#039#039') then'#010+
+  '    BaseInstallDir:=BD;'#010+
+  #010+
+  '  // Where to find ','the units by default'#010+
+  '  if (FGlobalUnitDir='#039#039') then'#010+
+  '    GlobalUnitDir:=IncludeTrailingPathDelimiter(BD)+'#039'units'#039'+Pa'+
+  'thDelim+Target;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                          ','  TCustomInstaller'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'constructor TCustomInstaller.Create(AOwner: TComponent);'#010+
+  'begin'#010+
+  '  Dictionary:=DictionaryClass.Create(Nil);'#010+
+  '  AnalyzeOptions;'#010+
+  '  CreatePackages;'#010,
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TCustomInstaller.Destroy;'#010+
+  'begin'#010+
+  '  FreeAndNil(Defaults);'#010+
+  '  FreeAndNil(Dictionary);'#010+
+  '  inherited destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Log(Level: TVerboseLevel; const Msg: String'+
+  ');'#010+
+  'begin'#010+
+  '  If Level in FLogLevels then'#010+
+  '   ',' Writeln(StdErr,Msg);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.CreatePackages;'#010+
+  'begin'#010+
+  '  FPAckages:=TPackages.Create(TPackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.CreateBuildEngine;'#010+
+  'begin'#010+
+  '  FBuildEngine:=TBuildEngine.Create(Self);'#010+
+  '//  FBuildEngine.De','faults:=Defaults;'#010+
+  '  FBuildEngine.ListMode:=FListMode;'#010+
+  '  FBuildEngine.OnLog:[email protected];'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Error(const Msg: String);'#010+
+  'begin'#010+
+  '  Raise EInstallerError.Create(Msg);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Error(const Fmt:',' String; Args: array of c'+
+  'onst);'#010+
+  'begin'#010+
+  '  Raise EInstallerError.CreateFmt(Fmt,Args);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TCustomInstaller.AddPackage(const AName: String) : TPackage;'#010+
+  'begin'#010+
+  '  result:=FPackages.AddPackage(AName);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.A','nalyzeOptions;'#010+
+  #010+
+  '  Function CheckOption(Index : Integer;const Short,Long : String): Boo'+
+  'lean;'#010+
+  '  var'#010+
+  '    O : String;'#010+
+  '  begin'#010+
+  '    O:=Paramstr(Index);'#010+
+  '    Result:=(O='#039'-'#039'+short) or (O='#039'--'#039'+long) or (copy(O,'+
+  '1,Length(Long)+3)=('#039'--'#039'+long+'#039'='#039'));'#010+
+  '  en','d;'#010+
+  #010+
+  '  Function CheckCommand(Index : Integer;const Short,Long : String): Bo'+
+  'olean;'#010+
+  '  var'#010+
+  '    O : String;'#010+
+  '  begin'#010+
+  '    O:=Paramstr(Index);'#010+
+  '    Result:=(O='#039'-'#039'+short) or (O=long);'#010+
+  '  end;'#010+
+  #010+
+  '  Function OptionArg(Var Index : Integer) : String;'#010+
+  '  Var'#010,
+  '    P : Integer;'#010+
+  '  begin'#010+
+  '    if (Length(ParamStr(Index))>1) and (Paramstr(Index)[2]<>'#039'-'#039+
+  ') then'#010+
+  '      begin'#010+
+  '      If Index<ParamCount then'#010+
+  '        begin'#010+
+  '        Inc(Index);'#010+
+  '        Result:=Paramstr(Index);'#010+
+  '        end'#010+
+  '      else'#010+
+  '        Erro','r(SErrNeedArgument,[Index,ParamStr(Index)]);'#010+
+  '      end'#010+
+  '    else If length(ParamStr(Index))>2 then'#010+
+  '      begin'#010+
+  '      P:=Pos('#039'='#039',Paramstr(Index));'#010+
+  '      If (P=0) then'#010+
+  '        Error(SErrNeedArgument,[Index,ParamStr(Index)])'#010+
+  '      else'#010+
+  '        ','begin'#010+
+  '        Result:=Paramstr(Index);'#010+
+  '        Delete(Result,1,P);'#010+
+  '        end;'#010+
+  '      end;'#010+
+  '  end;'#010+
+  #010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  DefaultsFileName : string;'#010+
+  'begin'#010+
+  '  I:=0;'#010+
+  '  FListMode:=False;'#010+
+  '  FLogLevels:=DefaultMessages;'#010+
+  '  While (I<ParamCount) do'#010+
+  '  ','  begin'#010+
+  '    Inc(I);'#010+
+  '    if CheckOption(I,'#039'v'#039','#039'verbose'#039') then'#010+
+  '      FLogLevels:=AllMessages'#010+
+  '    else if CheckOption(I,'#039'd'#039','#039'debug'#039') then'#010+
+  '      FLogLevels:=AllMessages+[vlDebug]'#010+
+  '    else if CheckCommand(I,'#039'm'#039','#039'compile'#039') then'#010+
+  '      FRunMode:=rm','Compile'#010+
+  '    else if CheckCommand(I,'#039'b'#039','#039'build'#039') then'#010+
+  '      FRunMode:=rmBuild'#010+
+  '    else if CheckCommand(I,'#039'i'#039','#039'install'#039') then'#010+
+  '      FRunMode:=rmInstall'#010+
+  '    else if CheckCommand(I,'#039'c'#039','#039'clean'#039') then'#010+
+  '      FRunMode:=rmClean'#010+
+  '    else if CheckComm','and(I,'#039'a'#039','#039'archive'#039') then'#010+
+  '      FRunMode:=rmarchive'#010+
+  '    else if CheckCommand(I,'#039'M'#039','#039'manifest'#039') then'#010+
+  '      FRunMode:=rmManifest'#010+
+  '    else if CheckOption(I,'#039'h'#039','#039'help'#039') then'#010+
+  '      Usage('#039#039',[])'#010+
+  '    else if Checkoption(I,'#039'C'#039','#039'CPU'#039') then'#010+
+  '      Def','aults.CPU:=StringToCPU(OptionArg(I))'#010+
+  '    else if Checkoption(I,'#039'O'#039','#039'OS'#039') then'#010+
+  '      Defaults.OS:=StringToOS(OptionArg(I))'#010+
+  '    else if Checkoption(I,'#039't'#039','#039'target'#039') then'#010+
+  '      Defaults.Target:=OptionArg(I)'#010+
+  '    else if CheckOption(I,'#039'l'#039','#039'list-c','ommands'#039') then'#010+
+  '      FListMode:=True'#010+
+  '    else if Checkoption(I,'#039'P'#039','#039'prefix'#039') then'#010+
+  '      Defaults.Prefix:=OptionArg(I)'#010+
+  '    else if Checkoption(I,'#039'n'#039','#039'nofpccfg'#039') then'#010+
+  '      Defaults.NoFPCCfg:=true'#010+
+  '    else if CheckOption(I,'#039'B'#039','#039'baseinstalldir',#039') then'#010+
+  '      Defaults.BaseInstallDir:=OptionArg(I)'#010+
+  '    else if CheckOption(I,'#039'UL'#039','#039'localunitdir'#039') then'#010+
+  '      Defaults.LocalUnitDir:=OptionArg(I)'#010+
+  '    else if CheckOption(I,'#039'UG'#039','#039'globalunitdir'#039') then'#010+
+  '      Defaults.GlobalUnitDir:=OptionArg(I',')'#010+
+  '    else if CheckOption(I,'#039'r'#039','#039'compiler'#039') then'#010+
+  '      Defaults.Compiler:=OptionArg(I)'#010+
+  '    else if CheckOption(I,'#039'f'#039','#039'config'#039') then'#010+
+  '      DefaultsFileName:=OptionArg(I)'#010+
+  '    else'#010+
+  '      begin'#010+
+  '      Usage(SErrInValidArgument,[I,ParamStr(I)]);'#010,
+  '      end;'#010+
+  '    end;'#010+
+  '  If DefaultsFileName<>'#039#039' then'#010+
+  '    Defaults.LocalInit(DefaultsFileName);'#010+
+  '  Defaults.CompilerDefaults;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Usage(const FMT: String; Args: array of con'+
+  'st);'#010+
+  #010+
+  '  Procedure LogCmd(const LC,Msg : S','tring);'#010+
+  '  begin'#010+
+  '    Log(vlInfo,Format('#039' %-12s %s'#039',[LC,MSG]));'#010+
+  '  end;'#010+
+  #010+
+  '  Procedure LogOption(const C,LC,Msg : String);'#010+
+  '  begin'#010+
+  '    Log(vlInfo,Format('#039' -%s --%-16s %s'#039',[C,LC,MSG]));'#010+
+  '  end;'#010+
+  #010+
+  '  Procedure LogArgOption(const C,LC,Msg : String);'#010+
+  ' ',' begin'#010+
+  '    Log(vlInfo,Format('#039' -%s --%-20s %s'#039',[C,LC+'#039'='#039'+SVal'+
+  'ue,MSG]));'#010+
+  '  end;'#010+
+  #010+
+  'begin'#010+
+  '  If (FMT<>'#039#039') then'#010+
+  '    Log(vlInfo,Format(Fmt,Args));'#010+
+  '  Log(vlInfo,Format(SHelpUsage,[Paramstr(0)]));'#010+
+  '  Log(vlInfo,SHelpCommand);'#010+
+  '  LogCmd('#039'compile'#039',SHelp','Compile);'#010+
+  '  LogCmd('#039'build'#039',SHelpBuild);'#010+
+  '  LogCmd('#039'install'#039',SHelpInstall);'#010+
+  '  LogCmd('#039'clean'#039',SHelpClean);'#010+
+  '  LogCmd('#039'archive'#039',SHelpArchive);'#010+
+  '  LogCmd('#039'manifest'#039',SHelpManifest);'#010+
+  '  Log(vlInfo,SHelpCmdOptions);'#010+
+  '  LogOption('#039'h'#039','#039'help'#039',SHelpHelp);'#010,
+  '  LogOption('#039'l'#039','#039'list-commands'#039',SHelpList);'#010+
+  '  LogOption('#039'n'#039','#039'nofpccfg'#039',SHelpNoFPCCfg);'#010+
+  '  LogOption('#039'v'#039','#039'verbose'#039',SHelpVerbose);'#010+
+  '  LogArgOption('#039'C'#039','#039'CPU'#039',SHelpCPU);'#010+
+  '  LogArgOption('#039'O'#039','#039'OS'#039',SHelpOS);'#010+
+  '  LogArgOption('#039't'#039','#039'target'#039',SHelpTarget);'#010,
+  '  LogArgOption('#039'P'#039','#039'prefix'#039',SHelpPrefix);'#010+
+  '  LogArgOption('#039'B'#039','#039'baseinstalldir'#039',SHelpBaseInstalldi'+
+  'r);'#010+
+  '  LogArgOption('#039'UL'#039','#039'localunitdir'#039',SHelpLocalUnitdir);'+
+  #010+
+  '  LogArgOption('#039'UG'#039','#039'globalunitdir'#039',SHelpGlobalUnitdir'+
+  ');'#010+
+  '  LogArgOption('#039'r'#039','#039'compiler',#039',SHelpCompiler);'#010+
+  '  LogArgOption('#039'f'#039','#039'config'#039',SHelpConfig);'#010+
+  '  Log(vlInfo,'#039#039');'#010+
+  '  If (FMT<>'#039#039') then'#010+
+  '    halt(1)'#010+
+  '  else'#010+
+  '    halt(0);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Compile(Force: Boolean);'#010+
+  'begin'#010+
+  '  FBuildEngine.ForceCompile:=Force;'#010+
+  '  FBuildE','ngine.Compile(FPackages);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Clean;'#010+
+  'begin'#010+
+  '  BuildEngine.Clean(FPackages);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Install;'#010+
+  'begin'#010+
+  '  BuildEngine.Install(FPackages);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Archive;'#010+
+  'begin'#010+
+  '  /','/ Force generation of manifest.xml, this is required for the repo'+
+  'sitory'#010+
+  '  Manifest;'#010+
+  '  FBuildEngine.Archive(FPackages);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.Manifest;'#010+
+  'Var'#010+
+  '  L : TStrings;'#010+
+  'begin'#010+
+  '  L:=TStringList.Create;'#010+
+  '  Try'#010+
+  '    Log(vlDebug, For','mat(SDbgGenerating, [ManifestFile]));'#010+
+  '    L.Add('#039'<?xml version="1.0"?>'#039');'#010+
+  '    BuildEngine.GetManifest(FPackages,L);'#010+
+  '    L.SaveToFile(ManifestFile);'#010+
+  '  Finally'#010+
+  '    L.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCustomInstaller.CheckPackages;'#010+
+  'begin'#010+
+  '  If (FP','ackages.Count=0) then'#010+
+  '    Error(SErrNoPackagesDefined);'#010+
+  '  // Check for other obvious errors ?'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TCustomInstaller.Run : Boolean;'#010+
+  'begin'#010+
+  '  Result:=True;'#010+
+  '  try'#010+
+  '    CheckPackages;'#010+
+  '    CreateBuildEngine;'#010+
+  '    Case RunMode of'#010+
+  '      rm','Compile : Compile(False);'#010+
+  '      rmBuild   : Compile(True);'#010+
+  '      rmInstall : Install;'#010+
+  '      rmArchive : Archive;'#010+
+  '      rmClean    : Clean;'#010+
+  '      rmManifest : Manifest;'#010+
+  '    end;'#010+
+  '  except'#010+
+  '    On E : Exception do'#010+
+  '      begin'#010+
+  '      Log(vlError,','SErrInstaller);'#010+
+  '      Log(vlError,E.Message);'#010+
+  '      Result:=False;'#010+
+  '      end;'#010+
+  '  end;'#010+
+  '  // Force returning an exitcode to the shell'#010+
+  '  if not Result then'#010+
+  '    ExitCode:=1;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{***************************************************************','****'+
+  '*********'#010+
+  '                                TFPCInstaller'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'constructor TFPCInstaller.Create(AOwner: TComponent);'#010+
+  'begin'#010+
+  '  if assigned(Defaults) then'#010+
+  '    Error(SE','rrAlreadyInitialized);'#010+
+  '  Defaults:=TFPCDefaults.Create;'#010+
+  '  inherited Create(AOwner);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                                 TBasicInstaller'#010+
+  '**********************','**********************************************'+
+  '********}'#010+
+  #010+
+  'constructor TBasicInstaller.Create(AOwner: TComponent);'#010+
+  'begin'#010+
+  '  if assigned(Defaults) then'#010+
+  '    Error(SErrAlreadyInitialized);'#010+
+  '  Defaults:=TBasicDefaults.Create;'#010+
+  '  inherited Create(AOw','ner);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{*********************************************************************'+
+  '*******'#010+
+  '                                 TBuildEngine'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'constructor TBuildEngine','.Create(AOwner: TComponent);'#010+
+  'begin'#010+
+  '  inherited Create(AOwner);'#010+
+  '  // Maybe this should be the current directory ?'#010+
+  '  // Or have it as a command-line option.'#010+
+  '  // Would allow to put all '#039'installers'#039' in one dir and call t'+
+  'hem'#010+
+  '  // With --start-d','ir=/path/to/sources.'#010+
+  '  FStartDir:=includeTrailingPathDelimiter(GetCurrentDir);'#010+
+  '  FExternalPackages:=TPackages.Create(TPackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TBuildEngine.Destroy;'#010+
+  'begin'#010+
+  '  FreeAndNil(FExternalPackages);'#010+
+  '  inherited Destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'proce','dure TBuildEngine.SetTargetDir(const AValue: String);'#010+
+  'begin'#010+
+  '  FTargetDir:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Error(const Msg: String);'#010+
+  'begin'#010+
+  '  Raise EInstallerError.Create(Msg);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Error(const Fmt: String; cons','t Args: array of'+
+  ' const);'#010+
+  'begin'#010+
+  '  Raise EInstallerError.CreateFmt(Fmt,Args);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.ExecuteCommand(const Cmd,Args : String; IgnoreE'+
+  'rror : Boolean = False);'#010+
+  'Var'#010+
+  '  E : Integer;'#010+
+  'begin'#010+
+  '  Log(vlInfo,SInfoExecutingCommand,[C','md,Args]);'#010+
+  '  if ListMode then'#010+
+  '    Log(vlError,'#039'%s %s'#039',[Cmd,Args])'#010+
+  '  else'#010+
+  '    begin'#010+
+  '      // We should check cmd for spaces, and move all after first spac'+
+  'e to args.'#010+
+  '      E:=ExecuteProcess(cmd,args);'#010+
+  '      If (E<>0) and (not IgnoreError) the','n'#010+
+  '        Error(SErrExternalCommandFailed,[Cmd,E]);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.SysDirectoryExists(const ADir:string):Boolean;'#010+
+  'begin'#010+
+  '  result:=SysUtils.DirectoryExists(ADir);'#010+
+  '  if result then'#010+
+  '    Log(vlDebug,SDbgDirectoryExists,[A','Dir,SDbgFound])'#010+
+  '  else'#010+
+  '    Log(vlDebug,SDbgDirectoryExists,[ADir,SDbgNotFound]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.SysFileExists(const AFileName:string):Boolean;'#010+
+  'begin'#010+
+  '  result:=SysUtils.FileExists(AFileName);'#010+
+  '  if result then'#010+
+  '    Log(vlDebug,SD','bgFileExists,[AFileName,SDbgFound])'#010+
+  '  else'#010+
+  '    Log(vlDebug,SDbgFileExists,[AFileName,SDbgNotFound]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.SysCopyFile(Const Src,Dest : String);'#010+
+  'Var'#010+
+  '  D,S : String;'#010+
+  '  Fin,FOut : TFileStream;'#010+
+  '  Count : Int64;'#010+
+  '  A : In','teger;'#010+
+  'begin'#010+
+  '  Log(vlInfo,SInfoCopyingFile,[Src,Dest]);'#010+
+  '  FIn:=TFileStream.Create(Src,fmopenRead);'#010+
+  '  Try'#010+
+  '    D:=IncludeTrailingPathDelimiter(Dest);'#010+
+  '    If DirectoryExists(D) then'#010+
+  '      S:=D+ExtractFileName(Src)'#010+
+  '    else'#010+
+  '      S:=Dest;'#010+
+  '    F','Out:=TFileStream.Create(S,fmCreate);'#010+
+  '    Try'#010+
+  '      Count:=Fout.CopyFrom(FIn,0);'#010+
+  '      If (Count<>Fin.Size) then'#010+
+  '        Error(SErrCopyingFile,[Src,S]);'#010+
+  '    Finally'#010+
+  '      FreeAndNil(Fout);'#010+
+  '    end;'#010+
+  '    A:=FileGetDate(FIn.Handle);'#010+
+  '    If (A=-','1) then'#010+
+  '      log(vlWarning,SWarnFailedToGetTime,[Src])'#010+
+  '    else'#010+
+  '      if FileSetDate(S,A)<>0 then'#010+
+  '        Log(vlWarning,SWarnFailedToSetTime,[S]);'#010+
+  '  finally'#010+
+  '    FreeAndNil(Fin);'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.SysMoveFile(Const Src,De','st : String);'#010+
+  'Var'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  If DirectoryExists(IncludeTrailingPathDelimiter(Dest)) then'#010+
+  '    S:=IncludeTrailingPathDelimiter(Dest)+ExtractFileName(Src)'#010+
+  '  else'#010+
+  '    S:=Dest;'#010+
+  '  If Not RenameFile(Src,S) then'#010+
+  '    begin'#010+
+  '      Try'#010+
+  '     ','   SysCopyFile(Src,S);'#010+
+  '        SysDeleteFile(Src);'#010+
+  '      Except'#010+
+  '        On E : Exception Do'#010+
+  '          Error(SErrMovingFile,[Src,S]);'#010+
+  '      end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.SysDeleteFile(Const AFileName : String);'#010+
+  'begin'#010+
+  '  if not F','ileExists(AFileName) then'#010+
+  '    Log(vlWarning,SWarnFileDoesNotExist,[AFileName])'#010+
+  '  else If Not DeleteFile(AFileName) then'#010+
+  '    Error(SErrDeletingFile,[AFileName]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.SysArchiveFiles(List: TStrings;Const AFileName:'+
+  ' S','tring);'#010+
+  'begin'#010+
+  '  If Not (Assigned(OnArchivefiles) or Assigned(ArchiveFilesProc)) then'+
+  #010+
+  '    Raise EInstallerError.Create(SErrNoArchiveSupport);'#010+
+  '  If Assigned(ArchiveFilesProc) then'#010+
+  '    ArchiveFilesProc(AFileName,List)'#010+
+  '  else'#010+
+  '    OnArchiveFiles','(AFileName,List);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Log(Level: TVerboseLevel; const Msg: String);'#010+
+  'begin'#010+
+  '  If Assigned(FOnLog) then'#010+
+  '    FOnLog(Level,Msg);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Log(Level: TVerboseLevel; const Fmt: String;con'+
+  'st Args: arra','y of const);'#010+
+  'begin'#010+
+  '  Log(Level,Format(Fmt,Args));'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.EnterDir(ADir: String);'#010+
+  'Var'#010+
+  '  D : String;'#010+
+  'begin'#010+
+  '  D:=FStartDir;'#010+
+  '  D:=D+ADir;'#010+
+  '  Log(vlInfo,SInfoEnterDir,[D]);'#010+
+  '  If Not SetCurrentDir(D) then'#010+
+  '    Error(SErrChang','eDirFailed,[D]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CmdCopyFiles(List: TStrings; Const DestDir: Str'+
+  'ing);'#010+
+  #010+
+  'Var'#010+
+  '  Args : String;'#010+
+  '  I : Integer;'#010+
+  #010+
+  'begin'#010+
+  '  CmdCreateDir(DestDir);'#010+
+  '  If (Defaults.Copy<>'#039#039') then'#010+
+  '    begin'#010+
+  '      Args:=FileListToString(Li','st,'#039#039');'#010+
+  '      Args:=Args+'#039' '#039'+DestDir;'#010+
+  '      ExecuteCommand(Defaults.Copy,Args);'#010+
+  '    end'#010+
+  '  else'#010+
+  '    For I:=0 to List.Count-1 do'#010+
+  '      SysCopyFile(List[i],DestDir);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CmdCreateDir(const DestDir: String);'#010+
+  'begin'#010+
+  '  If',' (Defaults.MkDir<>'#039#039') then'#010+
+  '    ExecuteCommand(Defaults.MkDir,DestDir)'#010+
+  '  else'#010+
+  '    If not ForceDirectories(DestDir) then'#010+
+  '      Error(SErrCreatingDirectory,[DestDir]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CmdMoveFiles(List: TStrings; Const DestDir: S','t'+
+  'ring);'#010+
+  'Var'#010+
+  '  Args : String;'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  CmdCreateDir(DestDir);'#010+
+  '  If (Defaults.Move<>'#039#039') then'#010+
+  '    begin'#010+
+  '      Args:=FileListToString(List,'#039#039');'#010+
+  '      Args:=Args+'#039' '#039'+DestDir;'#010+
+  '      ExecuteCommand(Defaults.Move,Args);'#010+
+  '    end'#010+
+  '  else',#010+
+  '    For I:=0 to List.Count-1 do'#010+
+  '      SysMoveFile(List[i],DestDir);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CmdDeleteFiles(List: TStrings);'#010+
+  'Var'#010+
+  '  Args : String;'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  If (Defaults.Remove<>'#039#039') then'#010+
+  '    begin'#010+
+  '      Args:=FileListToStr','ing(List,'#039#039');'#010+
+  '      ExecuteCommand(Defaults.Remove,Args);'#010+
+  '    end'#010+
+  '  else'#010+
+  '    For I:=0 to List.Count-1 do'#010+
+  '      SysDeleteFile(List[i]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CmdArchiveFiles(List: TStrings; Const ArchiveFi'+
+  'le: String);'#010+
+  'Var'#010+
+  '  S,C,O : S','tring;'#010+
+  'begin'#010+
+  '  If (Defaults.Archive='#039#039') then'#010+
+  '    SysArchiveFiles(List,ArchiveFile)'#010+
+  '  else'#010+
+  '    begin'#010+
+  '      S:=FileListToString(List,'#039#039');'#010+
+  '      SplitCommand(Defaults.Archive,C,O);'#010+
+  '      If (O='#039#039') then'#010+
+  '        O:=ArchiveFile+'#039' '#039'+S'#010+
+  '      else'#010+
+  ' ','       O:=Substitute(O,['#039'ARCHIVE'#039',ArchiveFile,'#039'FILESORD'+
+  'IRS'#039']);'#010+
+  '      ExecuteCommand(C,O);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  'Function TBuildEngine.FileNewer(const Src,Dest : String) : Boolean;'#010+
+  #010+
+  'Var'#010+
+  '  DS,DD : Longint;'#010+
+  '  D1,D2 : TDateTime;'#010+
+  #010+
+  'begin'#010+
+  '  DS:=FileAge(S','rc);'#010+
+  '  DD:=FileAge(Dest);'#010+
+  '  D1:=FileDateToDateTime(DS);'#010+
+  '  D2:=FileDateToDateTime(DD);'#010+
+  '  Log(vlDebug,SDbgComparingFileTimes,[Src,DateTimeToStr(D1),Dest,DateT'+
+  'imeToStr(D2)]);'#010+
+  '  Result:=D1>=D2;'#010+
+  '  If Result then'#010+
+  '    Log(vlInfo,SInfoSourceNewerDe','st,[Src,DateTimeToStr(D1),Dest,Date'+
+  'TimeToStr(D2)]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.ExecuteCommands(Commands: TCommands; At: TComma'+
+  'ndAt);'#010+
+  'Var'#010+
+  '  C : TCommand;'#010+
+  '  I : Integer;'#010+
+  '  Cmd,O : String;'#010+
+  '  E : Boolean;'#010+
+  'begin'#010+
+  '  For I:=0 to Commands.Count-1',' do'#010+
+  '    begin'#010+
+  '      C:=Commands.CommandItems[i];'#010+
+  '      if (C.At=At) then'#010+
+  '        begin'#010+
+  '          E:=True;'#010+
+  '          If (C.SourceFile<>'#039#039') and (C.DestFile<>'#039#039')  then'+
+  #010+
+  '            E:=FileNewer(C.SourceFile,IncludeTrailingPathDelimiter(Dic'+
+  'tiona','ry.GetValue('#039'OUTPUTDIR'#039'))+C.DestFile);'#010+
+  '          If E then'#010+
+  '            begin'#010+
+  '            If Assigned(C.BeforeCommand) then'#010+
+  '              C.BeforeCommand(C);'#010+
+  '            O:=Substitute(C.Options,['#039'SOURCE'#039',C.SourceFile,'#039+
+  'DEST'#039',C.DestFile]);'#010+
+  '   ','         Cmd:=C.Command;'#010+
+  '            If (ExtractFilePath(Cmd)='#039#039') then'#010+
+  '              Cmd:=FileSearch(Cmd,GetEnvironmentvariable('#039'PATH'#039+
+  '));'#010+
+  '            ExecuteCommand(Cmd,O,C.IgnoreResult);'#010+
+  '            If Assigned(C.AfterCommand) then'#010+
+  '       ','       C.AfterCommand(C);'#010+
+  '            end;'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetTargetDir(APackage : TPackage; ATarget : TTar'+
+  'get; AbsolutePath : Boolean = False) : String;'#010+
+  'begin'#010+
+  '  If AbsolutePath then'#010+
+  '    Result:=IncludeTra','ilingPathDelimiter(FStartDir)'#010+
+  '  else'#010+
+  '    Result:='#039#039';'#010+
+  '  If (APackage.Directory<>'#039#039') then'#010+
+  '    Result:=Result+IncludeTrailingPathDelimiter(APackage.Directory);'#010+
+  '  If (ATarget.Directory<>'#039#039') then'#010+
+  '    Result:=IncludeTrailingPathDelimiter(Result+A','Target.Directory);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure TBuildEngine.LogSearchPath(const ASearchPathName:string;Path'+
+  ':TConditionalStrings; ACPU:TCPU;AOS:TOS;Const PathPrefix :String='#039#039+
+  ');'#010+
+  'var'#010+
+  '  Prefix : String;'#010+
+  '  I : Integer;'#010+
+  '  C : TConditionalString;'#010+
+  'begin'#010+
+  '  if',' PathPrefix<>'#039#039' then'#010+
+  '    Prefix:=IncludeTrailingPathDelimiter(PathPrefix)'#010+
+  '  else'#010+
+  '    Prefix:='#039#039';'#010+
+  '  for i:=0 to Path.Count-1 do'#010+
+  '    begin'#010+
+  '      C:=Path[I];'#010+
+  '      if (ACPU in C.CPUs) and (AOS in C.OSes) then'#010+
+  '        Log(vlDebug,SDbgSearchPath',',[ASearchPathName,Dictionary.Repla'+
+  'ceStrings(Prefix+C.Value)]);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.FindFileInPath(Path:TConditionalStrings; AFileNa'+
+  'me:String; var FoundPath:String;ACPU:TCPU;AOS:TOS; Const PathPrefix :S'+
+  'tring='#039#039'):Boolean;'#010+
+  'va','r'#010+
+  '  Prefix : String;'#010+
+  '  I : Integer;'#010+
+  '  C : TConditionalString;'#010+
+  'begin'#010+
+  '  Result:=false;'#010+
+  '  if PathPrefix<>'#039#039' then'#010+
+  '    Prefix:=IncludeTrailingPathDelimiter(PathPrefix)'#010+
+  '  else'#010+
+  '    Prefix:='#039#039';'#010+
+  '  for i:=0 to Path.Count-1 do'#010+
+  '    begin'#010+
+  '      C:=Path[','I];'#010+
+  '      if (ACPU in C.CPUs) and (AOS in C.OSes) then'#010+
+  '        begin'#010+
+  '          FoundPath:=IncludeTrailingPathDelimiter(Dictionary.ReplaceSt'+
+  'rings(Prefix+C.Value));'#010+
+  '          if FileExists(FoundPath+AFileName) then'#010+
+  '            begin'#010+
+  '         ','     result:=true;'#010+
+  '              exit;'#010+
+  '            end;'#010+
+  '        end;'#010+
+  '    end;'#010+
+  '  FoundPath:='#039#039';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure TBuildEngine.ResolveFileNames(APackage : TPackage; ACPU:TCPU'+
+  ';AOS:TOS);'#010+
+  'var'#010+
+  '  SD,SF  : String;'#010+
+  '  D   : TDependency;'#010+
+  '  T : TTarget',';'#010+
+  '  i,j : Integer;'#010+
+  'begin'#010+
+  '  Dictionary.AddVariable('#039'CPU'#039',CPUToString(ACPU));'#010+
+  '  Dictionary.AddVariable('#039'OS'#039',OSToString(AOS));'#010+
+  '  For I:=0 to APackage.Targets.Count-1 do'#010+
+  '    begin'#010+
+  '      T:=APackage.FTargets.TargetItems[I];'#010+
+  #010+
+  '      // Debug infor','mation'#010+
+  '      Log(vlDebug,SDbgResolvingSourcesOfTarget,[T.Name]);'#010+
+  '      LogSearchPath('#039'Source'#039',APackage.SourcePath,ACPU,AOS,APac'+
+  'kage.Directory);'#010+
+  '      LogSearchPath('#039'Include'#039',T.IncludePath,ACPU,AOS,APackage.'+
+  'Directory);'#010+
+  '      LogSearchPath('#039'I','nclude'#039',APackage.IncludePath,ACPU,AOS,'+
+  'APackage.Directory);'#010+
+  #010+
+  '      // Main source file'#010+
+  '      SD:=Dictionary.ReplaceStrings(T.Directory);'#010+
+  '      SF:=Dictionary.ReplaceStrings(T.SourceFileName);'#010+
+  '      if SD='#039#039' then'#010+
+  '        FindFileInPath(APacka','ge.SourcePath,SF,SD,ACPU,AOS,APackage.D'+
+  'irectory)'#010+
+  '      else'#010+
+  '        if APackage.Directory<>'#039#039' then'#010+
+  '          SD:=IncludeTrailingPathDelimiter(APackage.Directory)+SD;'#010+
+  '      if SD<>'#039#039' then'#010+
+  '        SD:=IncludeTrailingPathDelimiter(SD);'#010+
+  '      T','.FFullSourceFileName:=SD+SF;'#010+
+  '      Log(vlDebug,SDbgResolvedSourceFile,[T.SourceFileName,T.FFullSour'+
+  'ceFileName]);'#010+
+  #010+
+  '      // Include files'#010+
+  '      for j:=0 to T.Dependencies.Count-1 do'#010+
+  '        begin'#010+
+  '          D:=T.Dependencies[j];'#010+
+  '          if ','(D.DependencyType=depInclude) and DependencyOK(D)  then'+
+  #010+
+  '            begin'#010+
+  '              SD:=Dictionary.ReplaceStrings(D.Directory);'#010+
+  '              SF:=Dictionary.ReplaceStrings(D.Value);'#010+
+  '              if SD='#039#039' then'#010+
+  '                begin'#010+
+  '    ','              // first check the target specific path'#010+
+  '                  if not FindFileInPath(T.IncludePath,SF,SD,ACPU,AOS,A'+
+  'Package.Directory) then'#010+
+  '                    FindFileInPath(APackage.IncludePath,SF,SD,ACPU,AOS'+
+  ',APackage.Directory);'#010,
+  '                end'#010+
+  '              else'#010+
+  '                if APackage.Directory<>'#039#039' then'#010+
+  '                  SD:=IncludeTrailingPathDelimiter(APackage.Directory)'+
+  '+SD;'#010+
+  '               if SD<>'#039#039' then'#010+
+  '                 SD:=IncludeTrailingPathDelimiter','(SD);'#010+
+  '               D.FFullFileName:=SD+SF;'#010+
+  '               Log(vlDebug,SDbgResolvedIncludeFile,[D.Value,D.FFullFil'+
+  'eName]);'#010+
+  '             end;'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.NeedsCompile(APackage:TPackage;ATarget: TTarget',
+  '): Boolean;'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  D : TDependency;'#010+
+  '  T : TTarget;'#010+
+  '  OD,OFN : String;'#010+
+  'begin'#010+
+  '  Result:=False;'#010+
+  '  case ATarget.FTargetState of'#010+
+  '    tsNeedCompile :'#010+
+  '      begin'#010+
+  '        result:=true;'#010+
+  '        exit;'#010+
+  '      end;'#010+
+  '    tsNoCompile,'#010+
+  '    ts','Compiled :'#010+
+  '      exit;'#010+
+  '  end;'#010+
+  #010+
+  '  Log(vlDebug, Format(SDbgConsideringTarget, [ATarget.Name]));'#010+
+  #010+
+  '  if ATarget.TargetType in ProgramTargets then'#010+
+  '    OD:=GetBinOutputDir(APackage, True)'#010+
+  '  else'#010+
+  '    OD:=GetUnitsOutputDir(APackage, True);'#010+
+  '  If (OD','<>'#039#039') then'#010+
+  '    OD:=IncludeTrailingPathDelimiter(OD);'#010+
+  '  OFN:=OD+ATarget.GetOutPutFileName(Defaults.OS);'#010+
+  #010+
+  '  Result:=Not FileExists(OFN);'#010+
+  '  if Result then'#010+
+  '    Log(vlDebug,SDbgOutputNotYetAvailable,[OFN]);'#010+
+  #010+
+  '  // Check main source'#010+
+  '  If not Resul','t then'#010+
+  '    begin'#010+
+  '      if FileExists(ATarget.FullSourceFileName) then'#010+
+  '        Result:=FileNewer(ATarget.FullSourceFileName,OFN)'#010+
+  '    end;'#010+
+  #010+
+  '  // Check unit and include dependencies'#010+
+  '  If not Result then'#010+
+  '    begin'#010+
+  '      ResolveDependencies(ATar','get.Dependencies,ATarget.Collection as'+
+  ' TTargets);'#010+
+  '      I:=0;'#010+
+  '      for i:=0 to ATarget.Dependencies.Count-1 do'#010+
+  '        begin'#010+
+  '          D:=ATarget.Dependencies[i];'#010+
+  '          if (Defaults.CPU in D.CPUs) and (Defaults.OS in D.OSes) then'+
+  #010+
+  '     ','       begin'#010+
+  '              case D.DependencyType of'#010+
+  '                depUnit :'#010+
+  '                  begin'#010+
+  '                    T:=TTarget(D.Target);'#010+
+  '                    If (T=Nil) then'#010+
+  '                      Error(SErrDepUnknownTarget,[ATarget.Na','me,D.Val'+
+  'ue]);'#010+
+  '                    // If a dependent package is compiled we always ne'+
+  'ed to recompile'#010+
+  '                    Log(vldebug, SDbgDependencyOnUnit, [ATarget.Name,T'+
+  '.Name]);'#010+
+  '                    Result:=(T.State in [tsNeedCompile,tsComp','iled]) '+
+  'or NeedsCompile(APackage,T);'#010+
+  '                    if Result then'#010+
+  '                      Log(vldebug, SDbgDependencyUnitRecompiled, [T.Na'+
+  'me]);'#010+
+  '                  end;'#010+
+  '                depInclude :'#010+
+  '                  begin'#010+
+  '                 ','   if FileExists(D.FullFileName) then'#010+
+  '                      Result:=FileNewer(D.FullFileName,OFN)'#010+
+  '                  end;'#010+
+  '              end;'#010+
+  '              if result then'#010+
+  '                break;'#010+
+  '            end;'#010+
+  '        end;'#010+
+  '    end;'#010+
+  #010+
+  '  // Upa','te also target state so a second check is faster'#010+
+  '  if result then'#010+
+  '    begin'#010+
+  '      ATarget.FTargetState:=tsNeedCompile;'#010+
+  '      Log(vlDebug,SDbgMustCompile,[ATarget.Name]);'#010+
+  '    end'#010+
+  '  else'#010+
+  '    ATarget.FTargetState:=tsNoCompile;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function ','TBuildEngine.GetUnitDir(APackage:TPackage):String;'#010+
+  'begin'#010+
+  '  if (APackage.UnitDir='#039#039') and'#010+
+  '     (Defaults.LocalUnitDir<>'#039#039') then'#010+
+  '    begin'#010+
+  '      APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.LocalUni'+
+  'tDir)+APackage.Name;'#010+
+  '      if not ','SysDirectoryExists(APackage.UnitDir) then'#010+
+  '        APackage.UnitDir:='#039#039';'#010+
+  '    end;'#010+
+  '  if APackage.UnitDir='#039#039' then'#010+
+  '    begin'#010+
+  '      APackage.UnitDir:=IncludeTrailingPathDelimiter(Defaults.GlobalUn'+
+  'itDir)+APackage.Name;'#010+
+  '      if not SysDirectoryEx','ists(APackage.UnitDir) then'#010+
+  '        APackage.UnitDir:=DirNotFound;'#010+
+  '    end;'#010+
+  '  // Special error marker to prevent searches in case of error'#010+
+  '  if APackage.UnitDir=DirNotFound then'#010+
+  '    Result:='#039#039#010+
+  '  else'#010+
+  '    Result:=APackage.UnitDir;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'pro','cedure TBuildEngine.AddDependencyUnitPaths(L:TStrings;APackage: T'+
+  'Package);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  P : TPackage;'#010+
+  '  D : TDependency;'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  // Already processed?'#010+
+  '  S:=GetUnitDir(APackage);'#010+
+  '  if L.IndexOf(S)<>-1 then'#010+
+  '    exit;'#010+
+  '  /','/ Add this package and then dependencies'#010+
+  '  L.Add(S);'#010+
+  '  For I:=0 to APackage.Dependencies.Count-1 do'#010+
+  '    begin'#010+
+  '      D:=APackage.Dependencies[i];'#010+
+  '      if (D.DependencyType=depPackage) and'#010+
+  '         (Defaults.CPU in D.CPUs) and (Defaults.OS i','n D.OSes) then'#010+
+  '        begin'#010+
+  '          P:=TPackage(D.Target);'#010+
+  '          If Assigned(P) then'#010+
+  '            AddDependencyUnitPaths(L,P);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetCompilerCommand(APackage : TPackage; ATarget '+
+  ': TTarg','et) : String;'#010+
+  #010+
+  'Var'#010+
+  '  PD,OD : String;'#010+
+  '  L : TStringList;'#010+
+  '  i : Integer;'#010+
+  'begin'#010+
+  '  PD:=GetPackageDir(APackage,True);'#010+
+  #010+
+  '  Result := '#039#039';'#010+
+  #010+
+  '  //compiler configuration'#010+
+  '  if Defaults.NoFPCCfg then'#010+
+  '    Result := '#039'-n'#039';'#010+
+  #010+
+  '  // Compile mode'#010+
+  '  If ATarget.Mo','de<>cmFPC then'#010+
+  '    Result:=Result+'#039' -M'#039'+ModeToString(ATarget.Mode)'#010+
+  '  else If Defaults.Mode<>cmFPC then'#010+
+  '    Result:=Result+'#039' -M'#039'+ModeToString(Defaults.Mode);'#010+
+  '  // Output file paths'#010+
+  '  If ATarget.TargetType in ProgramTargets then'#010+
+  '    begin'#010+
+  '   ','   OD:=GetBinOutputDir(APackage,True);'#010+
+  '      Result:=Result+'#039' -FE'#039' + ExtractRelativePath(PD,OD);'#010+
+  '    end;'#010+
+  '  OD:=GetUnitsOutputDir(APackage,True);'#010+
+  '  Result := Result + '#039' -FU'#039' + ExtractRelativePath(PD,OD);'#010+
+  '  // Package Input file paths'#010+
+  '  AddC','onditionalStrings(Result,APackage.UnitPath,Defaults.CPU,Defaul'+
+  'ts.OS,'#039'-Fu'#039');'#010+
+  '  AddConditionalStrings(Result,APackage.IncludePath,Defaults.CPU,Defau'+
+  'lts.OS,'#039'-Fi'#039');'#010+
+  '  AddConditionalStrings(Result,APackage.ObjectPath,Defaults.CPU,Defaul'+
+  'ts.OS,'#039'-F','o'#039');'#010+
+  '  AddConditionalStrings(Result,ATarget.UnitPath,Defaults.CPU,Defaults.'+
+  'OS,'#039'-Fu'#039');'#010+
+  '  AddConditionalStrings(Result,ATarget.IncludePath,Defaults.CPU,Defaul'+
+  'ts.OS,'#039'-Fi'#039');'#010+
+  '  AddConditionalStrings(Result,ATarget.ObjectPath,Defaults.CPU,Default',
+  's.OS,'#039'-Fo'#039');'#010+
+  '  // Global unit dirs'#010+
+  '  L:=TStringList.Create;'#010+
+  '  L.Sorted:=true;'#010+
+  '  L.Duplicates:=dupIgnore;'#010+
+  '  AddDependencyUnitPaths(L,APackage);'#010+
+  '  for i:=0 to L.Count-1 do'#010+
+  '    Result:=Result+'#039' -Fu'#039'+L[i];'#010+
+  '  FreeAndNil(L);'#010+
+  '  // Custom Options'#010+
+  ' ',' If (Defaults.Options<>'#039#039') then'#010+
+  '    Result:=Result+'#039' '#039'+Defaults.Options;'#010+
+  '  If (APackage.Options<>'#039#039') then'#010+
+  '    Result:=Result+'#039' '#039'+APackage.Options;'#010+
+  '  If (ATarget.Options<>'#039#039') then'#010+
+  '    Result:=Result+'#039' '#039'+ATarget.Options;'#010+
+  '  // Add Filename to ','compile'#010+
+  '  Result:=Result+'#039' '#039'+ExtractRelativePath(PD, ExpandFileName(AT'+
+  'arget.FullSourceFileName));'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetCompiler : String;'#010+
+  'Var'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  // Cache in FCompiler for speed.'#010+
+  '  If (FCompiler='#039#039') then'#010+
+  '    beg','in'#010+
+  '    FCompiler:=Defaults.Compiler;'#010+
+  '    If (ExtractFilePath(FCompiler)='#039#039') then'#010+
+  '      begin'#010+
+  '      S:=FileSearch(FCompiler,GetEnvironmentVariable('#039'PATH'#039'));'+
+  #010+
+  '      If (S<>'#039#039') then'#010+
+  '         FCompiler:=S;'#010+
+  '      end;'#010+
+  '    end;'#010+
+  '  Result:=FCompiler',';'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Compile(APackage: TPackage; ATarget: TTarget);'#010+
+  'Var'#010+
+  '  S : String;'#010+
+  'begin'#010+
+  '  if ATarget.State in [tsNeutral,tsNeedCompile] then'#010+
+  '    begin'#010+
+  '      Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]);'#010+
+  '      ExecuteComman','ds(ATarget.Commands,caBeforeCompile);'#010+
+  '      If Assigned(ATarget.BeforeCompile) then'#010+
+  '        ATarget.BeforeCompile(ATarget);'#010+
+  '      S:=GetCompilerCommand(APackage,ATarget);'#010+
+  '      ExecuteCommand(GetCompiler,S);'#010+
+  '      ATarget.FTargetState:=tsCo','mpiled;'#010+
+  '      If Assigned(ATarget.AfterCompile) then'#010+
+  '        ATarget.AfterCompile(ATarget);'#010+
+  '      ExecuteCommands(ATarget.Commands,caAfterCompile);'#010+
+  '    end'#010+
+  '  else if ATarget.State<>tsCompiled then'#010+
+  '    Log(vlWarning, Format(SWarnAttemptingTo','CompileNonNeutralTarget, '+
+  '[ATarget.Name]));'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CompileDependencies(APackage:TPackage; ATarget:'+
+  ' TTarget);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  T : TTarget;'#010+
+  '  D : TDependency;'#010+
+  'begin'#010+
+  '  if ATarget.State in [tsCompiled,tsNoCompile] the','n'#010+
+  '    exit;'#010+
+  '  Log(vlDebug, Format(SDbgCompilingDependenciesOfTarget, [ATarget.Name'+
+  ']));'#010+
+  '  For I:=0 to ATarget.Dependencies.Count-1 do'#010+
+  '    begin'#010+
+  '      D:=ATarget.Dependencies[i];'#010+
+  '      if (D.DependencyType=depUnit) and'#010+
+  '         (Defaults.CPU ','in D.CPUs) and (Defaults.OS in D.OSes) then'#010+
+  '        begin'#010+
+  '          T:=TTarget(D.Target);'#010+
+  '          If Assigned(T) and (T<>ATarget) then'#010+
+  '            begin'#010+
+  '              // We don'#039't need to compile implicit units, they are'+
+  ' only'#010+
+  '             ',' // used for dependency checking'#010+
+  '              if (T.TargetType<>ttImplicitUnit) then'#010+
+  '                begin'#010+
+  '{$warning Circular dependency check is disabled}'#010+
+  '//                    Log(vlWarning,SWarnCircularDependency,[T.Name,T.'+
+  'Name])'#010+
+  '      ','            MaybeCompile(APackage,T);'#010+
+  '                end;'#010+
+  '            end'#010+
+  '          else'#010+
+  '            Error(SErrDepUnknownTarget,[ATarget.Name,D.Value]);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.MaybeCompile(APackage: TPackage; A','Target: TTa'+
+  'rget);'#010+
+  'begin'#010+
+  '  ResolveDependencies(ATarget.Dependencies,ATarget.Collection as TTarg'+
+  'ets);'#010+
+  '  CompileDependencies(APackage, ATarget);'#010+
+  '  if NeedsCompile(APackage, ATarget) then'#010+
+  '    begin'#010+
+  '      Compile(APackage,ATarget);'#010+
+  '      ATarget','.FTargetState:=tsCompiled;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TBuildEngine.GetPackageDir(APackage: TPackage; AbsolutePath: '+
+  'Boolean): String;'#010+
+  'begin'#010+
+  '  If AbsolutePath then'#010+
+  '    Result:= IncludeTrailingPathDelimiter(FStartDir)'#010+
+  '  else'#010+
+  '    Result:='#039#039';'#010+
+  '  Re','sult:=Result+APackage.Directory;'#010+
+  '  If (Result<>'#039#039') then'#010+
+  '    Result:= IncludeTrailingPathDelimiter(Result);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetOutputDir(AName: string; APackage : TPackage;'+
+  ' AbsolutePath : Boolean = False) : String;'#010+
+  'begin'#010+
+  '  If (T','argetDir<>'#039#039') then'#010+
+  '    Result:=IncludeTrailingPathDelimiter(TargetDir)'#010+
+  '  else'#010+
+  '    begin'#010+
+  '      If AbsolutePath then'#010+
+  '        Result:=IncludeTrailingPathDelimiter(FStartDir)'#010+
+  '      else'#010+
+  '        Result:='#039#039';'#010+
+  '      If (APackage.Directory<>'#039#039') then',#010+
+  '        Result:=IncludeTrailingPathDelimiter(Result+APackage.Directory'+
+  ');'#010+
+  '      Result := IncludeTrailingPathDelimiter(Result + AName + PathDeli'+
+  'm + Defaults.Target);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetUnitsOutputDir(APackage : TPackag','e; Absolut'+
+  'ePath : Boolean = False) : String;'#010+
+  'begin'#010+
+  '  Result := GetOutputDir('#039'units'#039', APackage, AbsolutePath);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.GetBinOutputDir(APackage : TPackage; AbsolutePat'+
+  'h : Boolean = False) : String;'#010+
+  'begin'#010+
+  '  Result := GetO','utputDir('#039'bin'#039', APackage, AbsolutePath);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CreateOutputDir(APackage: TPackage);'#010+
+  'Var'#010+
+  '  D : String;'#010+
+  '  i: integer;'#010+
+  'begin'#010+
+  '  //create a units directory'#010+
+  '  D:=GetUnitsOutputDir(APackage,True);'#010+
+  '  If not SysDirectoryExist','s(D) then'#010+
+  '    begin'#010+
+  '      Log(vlInfo,SInfoCreatingOutputDir,[D]);'#010+
+  '      CmdCreateDir(D);'#010+
+  '    end;'#010+
+  #010+
+  '  //also create a bin directory for programtargets'#010+
+  '  For i := 0 to Pred(APackage.Targets.Count) do'#010+
+  '  begin'#010+
+  '    if APackage.Targets.TargetItem','s[i].TargetType in ProgramTargets '+
+  'then'#010+
+  '    begin'#010+
+  '      D:=GetBinOutputDir(APackage,True);'#010+
+  '      If not SysDirectoryExists(D) then'#010+
+  '        begin'#010+
+  '          Log(vlInfo,SInfoCreatingOutputDir,[D]);'#010+
+  '          CmdCreateDir(D);'#010+
+  '        end;'#010+
+  '      ','exit; //do not continue loop, directory is made anyway'#010+
+  '    end;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.DependencyOK(ADependency : TDependency) : Boolea'+
+  'n;'#010+
+  'begin'#010+
+  '  Result:=(Defaults.CPU in ADependency.CPUs) and (Defaults.OS in ADepe'+
+  'ndency.OSes);',#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.TargetOK(ATarget : TTarget) : Boolean;'#010+
+  'begin'#010+
+  '  Result:=(Defaults.CPU in ATarget.CPUs) and (Defaults.OS in ATarget.O'+
+  'Ses);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.PackageOK(APackage : TPackage) : Boolean;'#010+
+  'begin'#010+
+  '  Result:=(D','efaults.CPU in APackage.CPUs) and (Defaults.OS in APacka'+
+  'ge.OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoBeforeCompile(APackage: TPackage);'#010+
+  'begin'#010+
+  '  ExecuteCommands(APackage.Commands,caBeforeCompile);'#010+
+  '  If Assigned(APackage.BeforeCompile) then'#010+
+  '    ','APackage.BeforeCompile(APackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoAfterCompile(APackage: TPackage);'#010+
+  'begin'#010+
+  '  If Assigned(APackage.AfterCompile) then'#010+
+  '    APackage.AfterCompile(APackage);'#010+
+  '  ExecuteCommands(APackage.Commands,caAfterCompile);'#010+
+  'en','d;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Compile(APackage: TPackage);'#010+
+  'Var'#010+
+  '  T : TTarget;'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  Log(vlInfo,SInfoCompilingPackage,[APackage.Name]);'#010+
+  '  If (APackage.Directory<>'#039#039') then'#010+
+  '    EnterDir(APackage.Directory);'#010+
+  '  CreateOutputDir(APa','ckage);'#010+
+  '  Dictionary.AddVariable('#039'UNITSOUTPUTDIR'#039',GetUnitsOutputDir(AP'+
+  'ackage));'#010+
+  '  Dictionary.AddVariable('#039'BINOUTPUTDIR'#039',GetBinOutputDir(APacka'+
+  'ge));'#010+
+  '  DoBeforeCompile(APackage);'#010+
+  '  Try'#010+
+  '    For I:=0 to APackage.Targets.Count-1 do'#010+
+  '      begin'#010+
+  ' ','       T:=APackage.Targets.TargetItems[i];'#010+
+  '        if (T.TargetType in [ttUnit,ttProgram]) then'#010+
+  '          begin'#010+
+  '            if TargetOK(T) then'#010+
+  '              begin'#010+
+  '                if FForceCompile then'#010+
+  '                  T.FTargetState:=tsNe','edCompile;'#010+
+  '                MaybeCompile(APackage,T);'#010+
+  '              end'#010+
+  '            else'#010+
+  '              begin'#010+
+  '                if not(Defaults.CPU in T.CPUs) then'#010+
+  '                  Log(vldebug, Format(SDbgTargetHasWrongCPU, [CPUsToSt'+
+  'ring(T.CPU','s)]));'#010+
+  '                if not(Defaults.OS in T.OSes) then'#010+
+  '                  Log(vldebug, Format(SDbgTargetHasWrongOS, [OSesToStr'+
+  'ing(T.OSes)]));'#010+
+  '              end;'#010+
+  '          end'#010+
+  '        else'#010+
+  '          log(vldebug, SDbgTargetIsNotAUnitOrProgr','am,[T.Name]);'#010+
+  '      end;'#010+
+  '    DoAfterCompile(APackage);'#010+
+  '  Finally'#010+
+  '    If (APackage.Directory<>'#039#039') then'#010+
+  '      EnterDir('#039#039');'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TBuildEngine.CheckExternalPackage(Const APackageName : String'+
+  '):TPackage;'#010+
+  'var'#010+
+  '  S : String;'#010+
+  '  I ',': Integer;'#010+
+  'begin'#010+
+  '  // Already checked?'#010+
+  '  I:=ExternalPackages.IndexOfName(APackageName);'#010+
+  '  if I<>-1 then'#010+
+  '    begin'#010+
+  '      result:=ExternalPackages.PackageItems[I];'#010+
+  '      exit;'#010+
+  '    end;'#010+
+  '  // Create new external package'#010+
+  '  Result:=ExternalPackag','es.AddPackage(APackageName);'#010+
+  '  Result.FTargetState:=tsNotFound;'#010+
+  '  // Load unit config'#010+
+  '  S:=GetUnitDir(Result);'#010+
+  '  if S<>'#039#039' then'#010+
+  '    begin'#010+
+  '      Log(vldebug, SDbgExternalDependency, [APackageName,S]);'#010+
+  '      Result.FTargetState:=tsInstalled;'#010+
+  ' ','     // Load unit config if it exists'#010+
+  '      S:=IncludeTrailingPathDelimiter(S)+UnitConfigFile;'#010+
+  '      if FileExists(S) then'#010+
+  '        begin'#010+
+  '          Log(vlDebug, Format(SDbgLoading, [S]));'#010+
+  '          Result.LoadUnitConfigFromFile(S);'#010+
+  '        e','nd;'#010+
+  '      // Check recursive implicit dependencies'#010+
+  '      CompileDependencies(Result);'#010+
+  '    end'#010+
+  '  else'#010+
+  '    Error(SErrDependencyNotFound,[APackageName]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.CompileDependencies(APackage: TPackage);'#010+
+  'Var'#010+
+  '  I : Integer;',#010+
+  '  P : TPackage;'#010+
+  '  D : TDependency;'#010+
+  'begin'#010+
+  '  For I:=0 to APackage.Dependencies.Count-1 do'#010+
+  '    begin'#010+
+  '      D:=APackage.Dependencies[i];'#010+
+  '      if (D.DependencyType=depPackage) and'#010+
+  '         (Defaults.CPU in D.CPUs) and (Defaults.OS in D.OSes) t','hen'#010+
+  '        begin'#010+
+  '          P:=TPackage(D.Target);'#010+
+  '          // If it already was compiled, then State<>tsNeutral, and it'+
+  ' won'#039't be compiled again.'#010+
+  '          If Assigned(P) and (P<>APackage) then'#010+
+  '            Compile(P)'#010+
+  '          else'#010+
+  '       ','     D.Target:=CheckExternalPackage(D.Value);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TBuildEngine.InstallPackageFiles(APAckage : TPackage; tt : TT'+
+  'argetType; Const Dest : String):Boolean;'#010+
+  'Var'#010+
+  '  List : TStringList;'#010+
+  '  PD,UD,BD : string;'#010+
+  'begin'#010+
+  ' ',' Result:=False;'#010+
+  '  List:=TStringList.Create;'#010+
+  '  Try'#010+
+  '    UD:=GetUnitsOutputDir(APackage);'#010+
+  '    BD:=GetBinOutputDir(APackage);'#010+
+  '    PD:=GetPackageDir(APackage);'#010+
+  '    APackage.GetInstallFiles(List,[tt],PD, UD, BD, Defaults.CPU, Defau'+
+  'lts.OS);'#010+
+  '    if',' (List.Count>0) then'#010+
+  '      begin'#010+
+  '        Result:=True;'#010+
+  '        CmdCopyFiles(List,Dest);'#010+
+  '      end;'#010+
+  '  Finally'#010+
+  '    List.Free;'#010+
+  '  end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoBeforeInstall(APackage: TPackage);'#010+
+  'begin'#010+
+  '  ExecuteCommands(APackage.Commands,','caBeforeInstall);'#010+
+  '  If Assigned(APackage.BeforeInstall) then'#010+
+  '    APackage.BeforeInstall(APackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoAfterInstall(APackage: TPackage);'#010+
+  'begin'#010+
+  '  If Assigned(APackage.AfterInstall) then'#010+
+  '    APackage.AfterInstall(A','Package);'#010+
+  '  ExecuteCommands(APackage.Commands,caAfterInstall);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Install(APackage: TPackage);'#010+
+  'Var'#010+
+  '  UC,D : String;'#010+
+  '  B : Boolean;'#010+
+  'begin'#010+
+  '  If (Apackage.State<>tsCompiled) then'#010+
+  '    Compile(APackage);'#010+
+  '  Log(vlInfo,S','InfoInstallingPackage,[APackage.Name]);'#010+
+  '  DoBeforeInstall(APackage);'#010+
+  '  // units'#010+
+  '  B:=false;'#010+
+  '  D:=IncludeTrailingPathDelimiter(Defaults.UnitInstallDir)+APackage.Na'+
+  'me;'#010+
+  '  if InstallPackageFiles(APAckage,ttUnit,D) then'#010+
+  '    B:=true;'#010+
+  '  if Install','PackageFiles(APAckage,ttImplicitUnit,D) then'#010+
+  '    B:=true;'#010+
+  '  // Unit (dependency) configuration if there were units installed'#010+
+  '  if B then'#010+
+  '    begin'#010+
+  '      UC:=IncludeTrailingPathDelimiter(D)+UnitConfigFile;'#010+
+  '      Log(vlInfo, Format(SDbgGenera','ting, [UC]));'#010+
+  '      APackage.SaveUnitConfigToFile(UC,Defaults.CPU,Defaults.OS);'#010+
+  '    end;'#010+
+  '  // Programs'#010+
+  '  D:=IncludeTrailingPathDelimiter(Defaults.BinInstallDir);'#010+
+  '  InstallPackageFiles(APAckage,ttProgram,D);'#010+
+  '  // Done.'#010+
+  '  APackage.FTargetStat','e:=tsInstalled;'#010+
+  '  DoAfterInstall(APackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoBeforeArchive(APackage: TPackage);'#010+
+  'begin'#010+
+  '  ExecuteCommands(APackage.Commands,caBeforeArchive);'#010+
+  '  If Assigned(APackage.BeforeArchive) then'#010+
+  '    APackage.BeforeArchive','(APackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoAfterArchive(APackage: TPackage);'#010+
+  'begin'#010+
+  '  If Assigned(APackage.AfterArchive) then'#010+
+  '    APackage.AfterArchive(APackage);'#010+
+  '  ExecuteCommands(APackage.Commands,caAfterArchive);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildE','ngine.Archive(APackage: TPackage);'#010+
+  'Var'#010+
+  '  L : TStringList;'#010+
+  '  PD,A : String;'#010+
+  '  i: integer;'#010+
+  '  ICPU : TCPU;'#010+
+  '  IOS  : TOS;'#010+
+  'begin'#010+
+  '  Log(vlInfo,SInfoArchivingPackage,[APackage.Name]);'#010+
+  '  DoBeforeArchive(Apackage);'#010+
+  '  L:=TStringList.Create;'#010+
+  '  L.Sorte','d:=true;'#010+
+  '  L.Duplicates:=dupIgnore;'#010+
+  '  Try'#010+
+  '    // Add fpmake.pp & manifest.xml always'#010+
+  '    PD:=GetPackageDir(APackage,False);'#010+
+  '    L.Add(PD+FPMakePPFile);'#010+
+  '    L.Add(PD+ManifestFile);'#010+
+  '    //get all files from all targets'#010+
+  '    for ICPU:=Low(TCPU)',' to high(TCPU) do'#010+
+  '      for IOS:=Low(TOS) to high(TOS) do'#010+
+  '        if OSCpupossible[IOS,ICPU] then'#010+
+  '          begin'#010+
+  '            ResolveFileNames(APackage,ICPU,IOS);'#010+
+  '            APackage.GetArchiveFiles(L, ICPU, IOS);'#010+
+  '          end;'#010+
+  '    //from',' sources'#010+
+  '    for i := 0 to APackage.Sources.Count-1 do'#010+
+  '      L.Add(APackage.Sources[i].Name);'#010+
+  #010+
+  '    //show all files'#010+
+  '    for i := 0 to L.Count-1 do'#010+
+  '      Log(vlInfo, Format(SInfoArchivingFile, [L[i]]));'#010+
+  #010+
+  '    A:=APackage.FileName + ZipExt;'#010+
+  #010+
+  '{','$ifdef HAS_UNIT_ZIPPER}'#010+
+  '    if not Assigned(ArchiveFilesProc) then'#010+
+  '      begin'#010+
+  '        FZipFile := TZipper.Create;'#010+
+  '        FZipFile.ZipFiles(A, L);'#010+
+  '      end'#010+
+  '    else'#010+
+  '{$endif HAS_UNIT_ZIPPER}'#010+
+  '      CmdArchiveFiles(L,A);'#010+
+  '  Finally'#010+
+  '    L.Free',';'#010+
+  #010+
+  '{$ifdef HAS_UNIT_ZIPPER}'#010+
+  '    if not Assigned(ArchiveFilesProc) then'#010+
+  '      FZipFile.Free;'#010+
+  '{$endif HAS_UNIT_ZIPPER}'#010+
+  '  end;'#010+
+  '  DoAfterArchive(Apackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoBeforeClean(APackage: TPackage);'#010+
+  'begin'#010+
+  '  ExecuteCommands','(APackage.Commands,caBeforeClean);'#010+
+  '  If Assigned(APackage.BeforeClean) then'#010+
+  '    APackage.BeforeClean(APackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.DoAfterClean(APackage: TPackage);'#010+
+  'begin'#010+
+  '  If Assigned(APackage.AfterClean) then'#010+
+  '    APackage.After','Clean(APackage);'#010+
+  '  ExecuteCommands(APackage.Commands,caAfterClean);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Clean(APackage: TPackage);'#010+
+  'Var'#010+
+  '  OU : String;'#010+
+  '  OB : String;'#010+
+  '  List : TStringList;'#010+
+  'begin'#010+
+  '  Log(vlInfo,SInfoCleaningPackage,[APackage.Name]);'#010+
+  ' ',' DoBeforeClean(Apackage);'#010+
+  '  OU:=IncludeTrailingPathDelimiter(GetUnitsOutputDir(APAckage));'#010+
+  '  OB:=IncludeTrailingPathDelimiter(GetBinOutputDir(APAckage));'#010+
+  '  List:=TStringList.Create;'#010+
+  '  try'#010+
+  '    APackage.GetCleanFiles(List,OU, OB, Defaults.CPU',',Defaults.OS);'#010+
+  '    if (List.Count>0) then'#010+
+  '      CmdDeleteFiles(List);'#010+
+  '  Finally'#010+
+  '    List.Free;'#010+
+  '  end;'#010+
+  '  DoAfterClean(Apackage);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TBuildEngine.NeedsCompile(APackage: TPackage): Boolean;'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  P : TPackage;'#010+
+  '  D :',' TDependency;'#010+
+  'begin'#010+
+  '  Result:=False;'#010+
+  '  case APackage.State of'#010+
+  '    tsNeedCompile :'#010+
+  '      begin'#010+
+  '        result:=true;'#010+
+  '        exit;'#010+
+  '      end;'#010+
+  '    tsCompiled :'#010+
+  '      exit;'#010+
+  '  end;'#010+
+  #010+
+  '  I:=0;'#010+
+  '  For I:=0 to APackage.Dependencies.Count-1 do'#010+
+  '    beg','in'#010+
+  '      D:=APackage.Dependencies[i];'#010+
+  '      if (D.DependencyType=depPackage) and'#010+
+  '         (Defaults.CPU in D.CPUs) and (Defaults.OS in D.OSes) then'#010+
+  '        begin'#010+
+  '          P:=TPackage(D.Target);'#010+
+  '          if Assigned(P) and (P<>APackage) th','en'#010+
+  '            begin'#010+
+  '              Result:=NeedsCompile(P);'#010+
+  '              if Result then'#010+
+  '                exit;'#010+
+  '            end;'#010+
+  '        end;'#010+
+  '    end;'#010+
+  '  If Not Result then'#010+
+  '    begin'#010+
+  '      I:=0;'#010+
+  '      While (Not Result) and (I<APackage.Target','s.Count) do'#010+
+  '        begin'#010+
+  '          Result:=NeedsCompile(APackage,APackage.Targets.TargetItems[i'+
+  ']);'#010+
+  '          Inc(I);'#010+
+  '        end;'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure TBuildEngine.GetManifest(APackage : TPackage; Manifest : TSt'+
+  'rings);'#010+
+  'begin'#010+
+  '  APackag','e.GetManifest(Manifest);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Compile(Packages: TPackages);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  P : TPackage;'#010+
+  'begin'#010+
+  '  If Assigned(BeforeCompile) then'#010+
+  '    BeforeCompile(Self);'#010+
+  '  For I:=0 to Packages.Count-1 do'#010+
+  '    begin'#010+
+  '      P:=Pa','ckages.PackageItems[i];'#010+
+  '      If PackageOK(P) then'#010+
+  '        If (P.State=tsNeutral) then'#010+
+  '          begin'#010+
+  '            Log(vlDebug,SDbgConsideringPackage,[P.Name]);'#010+
+  '            if FForceCompile then'#010+
+  '              P.FTargetState:=tsNeedCompile;'#010,
+  '            ResolveDependencies(P.Dependencies,(P.Collection as TPacka'+
+  'ges));'#010+
+  '            CompileDependencies(P);'#010+
+  '            ResolveFileNames(P,Defaults.CPU,Defaults.OS);'#010+
+  '            If NeedsCompile(P) then'#010+
+  '              begin'#010+
+  '             ','   Compile(P);'#010+
+  '                P.FTargetState:=tsCompiled;'#010+
+  '              end;'#010+
+  '          end;'#010+
+  '    end;'#010+
+  '  If Assigned(AfterCompile) then'#010+
+  '    AfterCompile(Self);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Install(Packages: TPackages);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  ','P : TPackage;'#010+
+  'begin'#010+
+  '  If Assigned(BeforeInstall) then'#010+
+  '    BeforeInstall(Self);'#010+
+  '  For I:=0 to Packages.Count-1 do'#010+
+  '    begin'#010+
+  '      P:=Packages.PackageItems[i];'#010+
+  '      If PackageOK(P) then'#010+
+  '        Install(P);'#010+
+  '    end;'#010+
+  '  If Assigned(AfterInstall',') then'#010+
+  '    AfterInstall(Self);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Archive(Packages: TPackages);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  '  P : TPackage;'#010+
+  'begin'#010+
+  '  If Assigned(BeforeArchive) then'#010+
+  '    BeforeArchive(Self);'#010+
+  '  Log(vlDebug, SDbgBuildEngineArchiving);'#010+
+  '  For I',':=0 to Packages.Count-1 do'#010+
+  '    begin'#010+
+  '    P:=Packages.PackageItems[i];'#010+
+  '    If PackageOK(P) then'#010+
+  '      Archive(P);'#010+
+  '    end;'#010+
+  '  If Assigned(AfterArchive) then'#010+
+  '    AfterArchive(Self);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TBuildEngine.Clean(Packages: TPackages);'#010+
+  'Var',#010+
+  '  I : Integer;'#010+
+  '  P : TPackage;'#010+
+  'begin'#010+
+  '  If Assigned(BeforeClean) then'#010+
+  '    BeforeClean(Self);'#010+
+  '  Log(vldebug, SDbgBuildEngineCleaning);'#010+
+  '  For I:=0 to Packages.Count-1 do'#010+
+  '    begin'#010+
+  '    P:=Packages.PackageItems[i];'#010+
+  '    If PackageOK(P) then'#010+
+  '    ','  Clean(P);'#010+
+  '    end;'#010+
+  '  If Assigned(AfterClean) then'#010+
+  '    AfterClean(Self);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Procedure TBuildEngine.GetManifest(Packages : TPackages; Manifest : TS'+
+  'trings);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  If Assigned(BeforeManifest) then'#010+
+  '    BeforeManifest(S','elf);'#010+
+  '  Manifest.Add('#039'<packages>'#039');'#010+
+  '  For I:=0 to Packages.Count-1 do'#010+
+  '    GetManifest(Packages.PackageItems[i],Manifest);'#010+
+  '  Manifest.Add('#039'</packages>'#039');'#010+
+  '  If Assigned(AfterManifest) then'#010+
+  '    AfterManifest(Self);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{********************','***********************************************'+
+  '*********'#010+
+  '                                 TTarget'#010+
+  '**********************************************************************'+
+  '******}'#010+
+  #010+
+  'constructor TTarget.Create(ACollection: TCollection);'#010+
+  'begin'#010+
+  '  i','nherited Create(ACollection);'#010+
+  '  FInstall:=True;'#010+
+  '  FCPUs:=AllCPUs;'#010+
+  '  FOSes:=AllOSes;'#010+
+  '  FUnitPath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FIncludePath:=TConditionalStrings.Create(TConditionalString);'#010+
+  '  FObjectPath:=TConditionalStri','ngs.Create(TConditionalString);'#010+
+  '  FDependencies:=TDependencies.Create(TDependency);'#010+
+  '  FCommands:=TCOmmands.Create(TCommand);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TTarget.Destroy;'#010+
+  'begin'#010+
+  '  FreeAndNil(FUnitPath);'#010+
+  '  FreeAndNil(FObjectPath);'#010+
+  '  FreeAndNil(FIncludeP','ath);'#010+
+  '  FreeAndNil(FDependencies);'#010+
+  '  FreeAndNil(FCommands);'#010+
+  '  inherited Destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetSourceFileName: String;'#010+
+  'begin'#010+
+  '  Result:=Name+FExtension;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetUnitFileName: String;'#010+
+  'begin'#010+
+  '  Result:=Name+UnitE','xt;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetObjectFileName: String;'#010+
+  'begin'#010+
+  '  Result:=Name+ObjExt;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetRSTFileName: String;'#010+
+  'begin'#010+
+  '  Result:=Name+RSText;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetProgramFileName(AOS : TOS): String;'#010+
+  'begin'#010+
+  '  if AOS i','n [Go32v2,Win32,Win64,OS2] then'#010+
+  '    Result:=Name+ExeExt'#010+
+  '  else'#010+
+  '    Result:=Name;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TTarget.GetOutputFileName(AOs: TOS): String;'#010+
+  'begin'#010+
+  '  if TargetType in UnitTargets then'#010+
+  '    Result:=GetUnitFileName'#010+
+  '  else'#010+
+  '    Result:=GetProgra','mFileName(AOs);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TTarget.SetName(const AValue: String);'#010+
+  'Var'#010+
+  '  D,N,E : String;'#010+
+  'begin'#010+
+  '  N:=FixPath(AValue);'#010+
+  '  D:=ExtractFilePath(N);'#010+
+  '  E:=ExtractFileExt(N);'#010+
+  '  N:=ExtractFileName(N);'#010+
+  '  If (E<>'#039#039') then'#010+
+  '    N:=Copy(N,1,Length(N)-','Length(E))'#010+
+  '  else'#010+
+  '    E:=Defaults.SourceExt;'#010+
+  '  inherited SetName(N);'#010+
+  '  FExtension:=E;'#010+
+  '  FDirectory:=D;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TTarget.GetCleanFiles(List: TStrings; const APrefixU, APrefi'+
+  'xB : String; ACPU: TCPU; AOS : TOS);'#010+
+  'begin'#010+
+  '  If not(ACPU in ','CPUs) or not(AOS in OSes) then'#010+
+  '    exit;'#010+
+  '  List.Add(APrefixU + ObjectFileName);'#010+
+  '  If (TargetType in [ttUnit,ttImplicitUnit,ttExampleUnit, ttCleanOnlyU'+
+  'nit]) then'#010+
+  '    List.Add(APrefixU + UnitFileName)'#010+
+  '  else If (TargetType in [ttProgram,ttExa','mpleProgram]) then'#010+
+  '    List.Add(APrefixB + GetProgramFileName(AOS));'#010+
+  '  If ResourceStrings then'#010+
+  '    List.Add(APrefixU + RSTFileName);'#010+
+  '  // Maybe add later ?  AddConditionalStrings(List,CleanFiles);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TTarget.GetInstallFiles(Li','st: TStrings; const APrefixU, AP'+
+  'refixB: String; ACPU: TCPU; AOS : TOS);'#010+
+  'begin'#010+
+  '  If not(ACPU in CPUs) or not(AOS in OSes) then'#010+
+  '    exit;'#010+
+  '  If Not (TargetType in [ttProgram,ttExampleProgram]) then'#010+
+  '    List.Add(APrefixU + ObjectFileName);'#010+
+  '  If',' (TargetType in [ttUnit,ttImplicitUnit,ttExampleUnit]) then'#010+
+  '    List.Add(APrefixU + UnitFileName)'#010+
+  '  else If (TargetType in [ttProgram,ttExampleProgram]) then'#010+
+  '    List.Add(APrefixB + GetProgramFileName(AOS));'#010+
+  '  If ResourceStrings then'#010+
+  '    Li','st.Add(APrefixU + RSTFileName);'#010+
+  '  // Maybe add later ?  AddConditionalStrings(List,InstallFiles);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TTarget.GetArchiveFiles(List: TStrings; ACPU: TCPU; AOS : TO'+
+  'S);'#010+
+  'var'#010+
+  '  i : integer;'#010+
+  '  D : TDependency;'#010+
+  'begin'#010+
+  '  If not(ACPU in ','CPUs) or not(AOS in OSes) then'#010+
+  '    exit;'#010+
+  '  // Main source'#010+
+  '  List.Add(FullSourceFileName);'#010+
+  '  // Includes'#010+
+  '  for i:=0 to Dependencies.Count-1 do'#010+
+  '    begin'#010+
+  '      D:=Dependencies[i];'#010+
+  '      if (D.DependencyType=depInclude) and'#010+
+  '         (ACPU in D','.CPUs) and (AOS in D.OSes) then'#010+
+  '        List.Add(D.FullFileName);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{ TSource }'#010+
+  #010+
+  'constructor TSource.Create(ACollection: TCollection);'#010+
+  'begin'#010+
+  '  inherited Create(ACollection);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TSource.Destroy;'#010+
+  'begin'#010+
+  '  inherited',' Destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{ TCommands }'#010+
+  #010+
+  'function TCommands.GetCommand(const Dest : String): TCommand;'#010+
+  'begin'#010+
+  '  Result:=TCommand(ItemByName(Dest));'#010+
+  'end;'#010+
+  #010+
+  'function TCommands.GetCommandItem(Index : Integer): TCommand;'#010+
+  'begin'#010+
+  '  Result:=TCommand(Items[Ind','ex]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TCommands.SetCommandItem(Index : Integer; const AValue: TCom'+
+  'mand);'#010+
+  'begin'#010+
+  '  Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TCommands.AddCommand(const Cmd: String) : TCommand;'#010+
+  'begin'#010+
+  '  Result:=AddCommand(fdefaultAt,Cmd,'#039#039','#039#039','#039#039');',#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCommands.AddCommand(const Cmd, Options: String): TCommand;'#010+
+  'begin'#010+
+  '  Result:=AddCommand(fdefaultAt,Cmd,Options,'#039#039','#039#039');'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCommands.AddCommand(const Cmd, Options, Dest, Source: String'+
+  ' ): TCommand;'#010+
+  'begin'#010+
+  '  Result',':=AddCommand(fdefaultAt,Cmd,options,Dest,Source);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TCommands.AddCommand(At: TCommandAt; const Cmd: String) : TCo'+
+  'mmand;'#010+
+  'begin'#010+
+  '  Result:=AddCommand(At,Cmd,'#039#039','#039#039','#039#039');'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCommands.AddCommand(At: TCommandAt; const Cm','d, Options: St'+
+  'ring  ): TCommand;'#010+
+  'begin'#010+
+  '  Result:=AddCommand(At,Cmd,Options,'#039#039','#039#039');'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TCommands.AddCommand(At: TCommandAt; const Cmd, Options, Dest'+
+  ', Source: String): TCommand;'#010+
+  'begin'#010+
+  '  Result:=Add as TCommand;'#010+
+  '  Result.Command:=','Cmd;'#010+
+  '  Result.Options:=Options;'#010+
+  '  Result.At:=At;'#010+
+  '  Result.SourceFile:=Source;'#010+
+  '  Result.DestFile:=Dest;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{ TConditionalStrings }'#010+
+  #010+
+  'Constructor TConditionalStrings.Create(AClass:TClass);'#010+
+  'begin'#010+
+  '  inherited Create;'#010+
+  '  FCSClass:=AClass;'#010+
+  'end;',#010+
+  #010+
+  #010+
+  'function TConditionalStrings.GetConditionalString(Index : Integer): TC'+
+  'onditionalString;'#010+
+  'begin'#010+
+  '  Result:=TConditionalString(Items[Index]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TConditionalStrings.SetConditionalString(Index : Integer; co'+
+  'nst AValue: TCondition','alString);'#010+
+  'begin'#010+
+  '  Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TConditionalStrings.Add(Const Value : String) : TConditionalS'+
+  'tring;'#010+
+  'begin'#010+
+  '  result:=Add(Value,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TConditionalStrings.Add(Const Value : String;const CPUs',':TCP'+
+  'Us) : TConditionalString;'#010+
+  'begin'#010+
+  '  result:=Add(Value,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TConditionalStrings.Add(Const Value : String;const OSes:TOSes'+
+  ') : TConditionalString;'#010+
+  'begin'#010+
+  '  result:=Add(Value,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TConditiona','lStrings.Add(Const Value : String;const CPUs:TCP'+
+  'Us;const OSes:TOSes) : TConditionalString;'#010+
+  'begin'#010+
+  '  Result:=FCSClass.Create as TConditionalString;'#010+
+  '  Result.Value:=Value;'#010+
+  '  Result.OSes:=OSes;'#010+
+  '  Result.CPUs:=CPUs;'#010+
+  '  inherited Add(Result);'#010+
+  'end;',#010+
+  #010+
+  #010+
+  'function TDependencies.GetDependency(Index : Integer): TDependency;'#010+
+  'begin'#010+
+  '  Result:=TDependency(Items[Index]);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TDependencies.SetDependency(Index : Integer; const AValue: T'+
+  'Dependency);'#010+
+  'begin'#010+
+  '  Items[Index]:=AValue;'#010+
+  'end;'#010+
+  #010,
+  #010+
+  'Function TDependencies.Add(Const Value : String) : TDependency;'#010+
+  'begin'#010+
+  '  result:=Add(Value,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.Add(Const Value : String;const CPUs:TCPUs) : TD'+
+  'ependency;'#010+
+  'begin'#010+
+  '  result:=Add(Value,CPUs,AllOSes);'#010+
+  'en','d;'#010+
+  #010+
+  #010+
+  'Function TDependencies.Add(Const Value : String;const OSes:TOSes) : TD'+
+  'ependency;'#010+
+  'begin'#010+
+  '  result:=Add(Value,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.Add(Const Value : String;const CPUs:TCPUs;const'+
+  ' OSes:TOSes) : TDependency;'#010+
+  'begin'#010+
+  '  ','Result:=inherited Add(Value,CPUs,OSes) as TDependency;'#010+
+  '  Result.Target:=nil;'#010+
+  '  Result.FDependencyType:=depPackage;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddUnit(Const Value : String) : TDependency;'#010+
+  'begin'#010+
+  '  result:=AddUnit(Value,AllCPUs,AllOSes);'#010+
+  'en','d;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddUnit(Const Value : String;const CPUs:TCPUs) '+
+  ': TDependency;'#010+
+  'begin'#010+
+  '  result:=AddUnit(Value,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddUnit(Const Value : String;const OSes:TOSes) '+
+  ': TDependency;'#010+
+  'begin'#010+
+  '  resul','t:=AddUnit(Value,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddUnit(Const Value : String;const CPUs:TCPUs;c'+
+  'onst OSes:TOSes) : TDependency;'#010+
+  'begin'#010+
+  '  Result:=inherited Add(Value,CPUs,OSes) as TDependency;'#010+
+  '  Result.Target:=nil;'#010+
+  '  Result.FDepe','ndencyType:=depUnit;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddInclude(Const Value : String) : TDependency;'+
+  #010+
+  'begin'#010+
+  '  result:=AddInclude(Value,AllCPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddInclude(Const Value : String;const CPUs:TCPU'+
+  's) : TDepende','ncy;'#010+
+  'begin'#010+
+  '  result:=AddInclude(Value,CPUs,AllOSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddInclude(Const Value : String;const OSes:TOSe'+
+  's) : TDependency;'#010+
+  'begin'#010+
+  '  result:=AddInclude(Value,AllCPUs,OSes);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function TDependencies.AddInclude(Con','st Value : String;const CPUs:TC'+
+  'PUs;const OSes:TOSes) : TDependency;'#010+
+  'Var'#010+
+  '  D,N : String;'#010+
+  'begin'#010+
+  '  N:=FixPath(Value);'#010+
+  '  D:=ExtractFilePath(N);'#010+
+  '  N:=ExtractFileName(N);'#010+
+  '  if ExtractFileExt(N)='#039#039' then'#010+
+  '    ChangeFileExt(N,IncExt);'#010+
+  '  Result:=inher','ited Add(N,CPUs,OSes) as TDependency;'#010+
+  '  Result.FDirectory:=D;'#010+
+  '  Result.FDependencyType:=depInclude;'#010+
+  'end;'#010+
+  #010+
+  '{ Default Instances }'#010+
+  #010+
+  'var'#010+
+  '  DefInstaller : TCustomInstaller;'#010+
+  #010+
+  'Function Installer(InstallerClass: TInstallerClass): TCustomInstaller;'+
+  #010,
+  'begin'#010+
+  '  If Not Assigned(DefInstaller) then'#010+
+  '    DefInstaller:=InstallerClass.Create(Nil);'#010+
+  '  Result:=DefInstaller;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function Installer: TCustomInstaller;'#010+
+  'begin'#010+
+  '  Result := Installer(TFPCInstaller);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  '{ TValueItem }'#010+
+  #010+
+  'constructor TVa','lueItem.Create(AValue: String);'#010+
+  'begin'#010+
+  '  FValue:=AValue;'#010+
+  'end;'#010+
+  #010+
+  '{ TFunctionItem }'#010+
+  #010+
+  'constructor TFunctionItem.Create(AFunc: TReplaceFunction);'#010+
+  'begin'#010+
+  '  FFunc:=AFunc;'#010+
+  'end;'#010+
+  #010+
+  '{ TDictionary }'#010+
+  #010+
+  'constructor TDictionary.Create(AOwner: TComponent);'#010+
+  'beg','in'#010+
+  '  inherited Create(AOwner);'#010+
+  '  FList:=TStringList.Create;'#010+
+  '  FList.Sorted:=True;'#010+
+  '  FList.Duplicates:=dupError;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'destructor TDictionary.Destroy;'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  For I:=0 to Flist.Count-1 do'#010+
+  '    FList.Objects[i].Free;'#010+
+  '  Free','AndNil(FList);'#010+
+  '  inherited Destroy;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TDictionary.AddVariable(const AName, Value: String);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  I:=Flist.IndexOf(AName);'#010+
+  '  If I=-1 then'#010+
+  '    I:=FList.Add(Aname)'#010+
+  '  else'#010+
+  '    Flist.Objects[i].Free;'#010+
+  '  Flist.O','bjects[i]:=TValueItem.Create(Value);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TDictionary.AddFunction(const AName: String; FReplacement: T'+
+  'ReplaceFunction);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  I:=Flist.IndexOf(AName);'#010+
+  '  If I=-1 then'#010+
+  '    I:=Flist.Add(AName)'#010+
+  '  else'#010+
+  '    Flist.','Objects[i].Free;'#010+
+  '  Flist.Objects[i]:=TFunctionItem.Create(FReplacement);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'procedure TDictionary.RemoveItem(const AName: String);'#010+
+  'Var'#010+
+  '  I : Integer;'#010+
+  'begin'#010+
+  '  I:=Flist.IndexOf(AName);'#010+
+  '  If (I<>-1) then'#010+
+  '    begin'#010+
+  '    FList.Objects[i].Free',';'#010+
+  '    FList.Delete(I);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TDictionary.GetValue(const AName: String): String;'#010+
+  'begin'#010+
+  '  Result:=GetValue(AName,'#039#039');'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TDictionary.GetValue(const AName,Args: String): String;'#010+
+  'Var'#010+
+  '  O : TObject;'#010+
+  '  I : Integer;',#010+
+  'begin'#010+
+  '  I:=Flist.IndexOf(AName);'#010+
+  '  If (I=-1) then'#010+
+  '    Raise EDictionaryError.CreateFmt(SErrNoDictionaryItem,[AName]);'#010+
+  '  O:=Flist.Objects[I];'#010+
+  '  If O is TValueItem then'#010+
+  '    Result:=TValueItem(O).FValue'#010+
+  '  else'#010+
+  '    Result:=TFunctionItem(O).FFu','nc(AName,Args);'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'function TDictionary.ReplaceStrings(Const ASource: String): String;'#010+
+  'Var'#010+
+  '  S,FN,FV : String;'#010+
+  '  P: Integer;'#010+
+  'begin'#010+
+  '  Result:='#039#039';'#010+
+  '  S:=ASource;'#010+
+  '  P:=Pos('#039'$('#039',S);'#010+
+  '  While (P<>0) do'#010+
+  '    begin'#010+
+  '      Result:=Result+Copy(S,1,P','-1);'#010+
+  '      Delete(S,1,P+1);'#010+
+  '      P:=Pos('#039')'#039',S);'#010+
+  '      FN:=Copy(S,1,P-1);'#010+
+  '      Delete(S,1,P);'#010+
+  '      P:=Pos('#039' '#039',FN);'#010+
+  '      If (P<>0) then // function arguments ?'#010+
+  '        begin'#010+
+  '        FV:=FN;'#010+
+  '        FN:=Copy(FN,1,P);'#010+
+  '        System.Delete(','FV,1,P);'#010+
+  '        end'#010+
+  '      else'#010+
+  '        FV:='#039#039';'#010+
+  '      Result:=Result+GetValue(FN,FV);'#010+
+  '      P:=Pos('#039'$('#039',S);'#010+
+  '    end;'#010+
+  '  Result:=Result+S;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Function Substitute(Const Source : String; Macros : Array of string) :'+
+  ' String;'#010+
+  'Var'#010+
+  '  I : Integer',';'#010+
+  'begin'#010+
+  '  I:=0;'#010+
+  '  While I<High(Macros) do'#010+
+  '    begin'#010+
+  '      Dictionary.AddVariable(Macros[i],Macros[I+1]);'#010+
+  '      Inc(I,2);'#010+
+  '    end;'#010+
+  '  Result:=Dictionary.ReplaceStrings(Source);'#010+
+  '  While I<High(Macros) do'#010+
+  '    begin'#010+
+  '      Dictionary.RemoveItem(M','acros[i]);'#010+
+  '      Inc(I,2);'#010+
+  '    end;'#010+
+  'end;'#010+
+  #010+
+  #010+
+  'Initialization'#010+
+  '  OnGetApplicationName:=@GetFPMakeName;'#010+
+  #010+
+  'Finalization'#010+
+  '  FreeAndNil(DefInstaller);'#010+
+  '  FreeAndNil(Dictionary);'#010+
+  '  FreeAndNil(Defaults);'#010+
+  'end.'#010
+);

+ 102 - 102
utils/fppkg/fppkg.lpi

@@ -2,7 +2,7 @@
 <CONFIG>
   <ProjectOptions>
     <PathDelim Value="/"/>
-    <Version Value="5"/>
+    <Version Value="6"/>
     <General>
       <Flags>
         <MainUnitHasUsesSectionForAllUnits Value="False"/>
@@ -12,7 +12,7 @@
       <MainUnit Value="0"/>
       <IconPath Value=".\"/>
       <TargetFileExt Value=""/>
-      <ActiveEditorIndexAtStart Value="3"/>
+      <ActiveEditorIndexAtStart Value="4"/>
     </General>
     <VersionInfo>
       <ProjectVersion Value=""/>
@@ -32,15 +32,15 @@
         <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
       </local>
     </RunParams>
-    <Units Count="37">
+    <Units Count="38">
       <Unit0>
         <Filename Value="fppkg.pp"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="fppkg"/>
-        <CursorPos X="131" Y="33"/>
-        <TopLine Value="18"/>
-        <EditorIndex Value="0"/>
-        <UsageCount Value="82"/>
+        <CursorPos X="49" Y="280"/>
+        <TopLine Value="270"/>
+        <EditorIndex Value="6"/>
+        <UsageCount Value="86"/>
         <Loaded Value="True"/>
       </Unit0>
       <Unit1>
@@ -49,7 +49,7 @@
         <UnitName Value="pkgoptions"/>
         <CursorPos X="41" Y="18"/>
         <TopLine Value="1"/>
-        <UsageCount Value="82"/>
+        <UsageCount Value="86"/>
       </Unit1>
       <Unit2>
         <Filename Value="fpmkcnst.inc"/>
@@ -76,9 +76,9 @@
         <IsPartOfProject Value="True"/>
         <UnitName Value="fprepos"/>
         <CursorPos X="1" Y="187"/>
-        <TopLine Value="165"/>
-        <EditorIndex Value="9"/>
-        <UsageCount Value="82"/>
+        <TopLine Value="163"/>
+        <EditorIndex Value="7"/>
+        <UsageCount Value="86"/>
         <Loaded Value="True"/>
       </Unit5>
       <Unit6>
@@ -87,9 +87,7 @@
         <UnitName Value="fpxmlrep"/>
         <CursorPos X="1" Y="43"/>
         <TopLine Value="43"/>
-        <EditorIndex Value="10"/>
-        <UsageCount Value="82"/>
-        <Loaded Value="True"/>
+        <UsageCount Value="86"/>
       </Unit6>
       <Unit7>
         <Filename Value="pkghandler.pp"/>
@@ -97,9 +95,7 @@
         <UnitName Value="pkghandler"/>
         <CursorPos X="56" Y="170"/>
         <TopLine Value="156"/>
-        <EditorIndex Value="1"/>
-        <UsageCount Value="82"/>
-        <Loaded Value="True"/>
+        <UsageCount Value="86"/>
       </Unit7>
       <Unit8>
         <Filename Value="pkgmkconv.pp"/>
@@ -107,26 +103,24 @@
         <UnitName Value="pkgmkconv"/>
         <CursorPos X="14" Y="53"/>
         <TopLine Value="29"/>
-        <UsageCount Value="82"/>
+        <UsageCount Value="86"/>
       </Unit8>
       <Unit9>
         <Filename Value="pkgdownload.pp"/>
         <IsPartOfProject Value="True"/>
-        <UnitName Value="pkgdownload"/>
+        <UnitName Value="pkgDownload"/>
         <CursorPos X="27" Y="144"/>
         <TopLine Value="129"/>
-        <EditorIndex Value="2"/>
-        <UsageCount Value="82"/>
-        <Loaded Value="True"/>
+        <UsageCount Value="86"/>
       </Unit9>
       <Unit10>
         <Filename Value="pkgmessages.pp"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="pkgmessages"/>
-        <CursorPos X="34" Y="45"/>
-        <TopLine Value="25"/>
-        <EditorIndex Value="6"/>
-        <UsageCount Value="82"/>
+        <CursorPos X="96" Y="73"/>
+        <TopLine Value="43"/>
+        <EditorIndex Value="2"/>
+        <UsageCount Value="86"/>
         <Loaded Value="True"/>
       </Unit10>
       <Unit11>
@@ -172,10 +166,10 @@
       <Unit17>
         <Filename Value="pkgcommands.pp"/>
         <UnitName Value="pkgcommands"/>
-        <CursorPos X="3" Y="73"/>
-        <TopLine Value="59"/>
-        <EditorIndex Value="5"/>
-        <UsageCount Value="39"/>
+        <CursorPos X="39" Y="265"/>
+        <TopLine Value="242"/>
+        <EditorIndex Value="1"/>
+        <UsageCount Value="41"/>
         <Loaded Value="True"/>
       </Unit17>
       <Unit18>
@@ -209,10 +203,10 @@
       <Unit22>
         <Filename Value="pkgrepos.pp"/>
         <UnitName Value="pkgrepos"/>
-        <CursorPos X="30" Y="60"/>
-        <TopLine Value="42"/>
-        <EditorIndex Value="8"/>
-        <UsageCount Value="30"/>
+        <CursorPos X="104" Y="109"/>
+        <TopLine Value="82"/>
+        <EditorIndex Value="4"/>
+        <UsageCount Value="32"/>
         <Loaded Value="True"/>
       </Unit22>
       <Unit23>
@@ -271,36 +265,36 @@
       <Unit31>
         <Filename Value="pkgfpmake.pp"/>
         <UnitName Value="pkgfpmake"/>
-        <CursorPos X="25" Y="100"/>
-        <TopLine Value="88"/>
-        <EditorIndex Value="4"/>
-        <UsageCount Value="18"/>
+        <CursorPos X="35" Y="218"/>
+        <TopLine Value="188"/>
+        <EditorIndex Value="0"/>
+        <UsageCount Value="20"/>
         <Loaded Value="True"/>
       </Unit31>
       <Unit32>
         <Filename Value="pkglnet.pp"/>
         <UnitName Value="pkglnet"/>
-        <CursorPos X="1" Y="1"/>
+        <CursorPos X="45" Y="32"/>
         <TopLine Value="1"/>
-        <EditorIndex Value="12"/>
+        <EditorIndex Value="8"/>
         <UsageCount Value="17"/>
         <Loaded Value="True"/>
       </Unit32>
       <Unit33>
         <Filename Value="pkgoptions.pp"/>
         <UnitName Value="pkgoptions"/>
-        <CursorPos X="53" Y="84"/>
-        <TopLine Value="59"/>
-        <EditorIndex Value="7"/>
-        <UsageCount Value="17"/>
+        <CursorPos X="49" Y="230"/>
+        <TopLine Value="210"/>
+        <EditorIndex Value="3"/>
+        <UsageCount Value="19"/>
         <Loaded Value="True"/>
       </Unit33>
       <Unit34>
         <Filename Value="pkgglobals.pp"/>
         <UnitName Value="pkgglobals"/>
-        <CursorPos X="1" Y="29"/>
-        <TopLine Value="29"/>
-        <EditorIndex Value="11"/>
+        <CursorPos X="1" Y="51"/>
+        <TopLine Value="19"/>
+        <EditorIndex Value="5"/>
         <UsageCount Value="17"/>
         <Loaded Value="True"/>
       </Unit34>
@@ -316,138 +310,144 @@
         <UnitName Value="pkgarchive"/>
         <CursorPos X="1" Y="74"/>
         <TopLine Value="69"/>
-        <EditorIndex Value="3"/>
         <UsageCount Value="12"/>
-        <Loaded Value="True"/>
       </Unit36>
+      <Unit37>
+        <Filename Value="/tmp/testcompileroptions.pas"/>
+        <UnitName Value="testcompileroptions"/>
+        <CursorPos X="1" Y="1"/>
+        <TopLine Value="1"/>
+        <UsageCount Value="10"/>
+      </Unit37>
     </Units>
     <JumpHistory Count="30" HistoryIndex="29">
       <Position1>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="1" Column="1" TopLine="1"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="706" Column="21" TopLine="688"/>
       </Position1>
       <Position2>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="80" Column="13" TopLine="74"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="751" Column="28" TopLine="733"/>
       </Position2>
       <Position3>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="181" Column="1" TopLine="169"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="768" Column="25" TopLine="748"/>
       </Position3>
       <Position4>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="38" Column="27" TopLine="15"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="842" Column="25" TopLine="824"/>
       </Position4>
       <Position5>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="76" Column="35" TopLine="62"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="883" Column="17" TopLine="850"/>
       </Position5>
       <Position6>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="185" Column="14" TopLine="158"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="894" Column="32" TopLine="876"/>
       </Position6>
       <Position7>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="256" Column="49" TopLine="242"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="907" Column="59" TopLine="889"/>
       </Position7>
       <Position8>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="23" Column="22" TopLine="15"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="909" Column="18" TopLine="891"/>
       </Position8>
       <Position9>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="91" Column="1" TopLine="78"/>
+        <Filename Value="fprepos.pp"/>
+        <Caret Line="914" Column="23" TopLine="896"/>
       </Position9>
       <Position10>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="46" Column="42" TopLine="32"/>
+        <Caret Line="99" Column="1" TopLine="80"/>
       </Position10>
       <Position11>
-        <Filename Value="pkgoptions.pp"/>
-        <Caret Line="306" Column="58" TopLine="293"/>
+        <Filename Value="fppkg.pp"/>
+        <Caret Line="55" Column="1" TopLine="37"/>
       </Position11>
       <Position12>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="46" Column="42" TopLine="32"/>
+        <Caret Line="69" Column="26" TopLine="55"/>
       </Position12>
       <Position13>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="58" Column="35" TopLine="40"/>
+        <Caret Line="79" Column="21" TopLine="57"/>
       </Position13>
       <Position14>
         <Filename Value="fprepos.pp"/>
-        <Caret Line="295" Column="46" TopLine="275"/>
+        <Caret Line="992" Column="39" TopLine="967"/>
       </Position14>
       <Position15>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="58" Column="27" TopLine="40"/>
+        <Caret Line="75" Column="21" TopLine="57"/>
       </Position15>
       <Position16>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="61" Column="52" TopLine="40"/>
+        <Filename Value="fppkg.pp"/>
+        <Caret Line="280" Column="5" TopLine="253"/>
       </Position16>
       <Position17>
-        <Filename Value="pkgcommands.pp"/>
-        <Caret Line="55" Column="11" TopLine="45"/>
+        <Filename Value="pkgrepos.pp"/>
+        <Caret Line="91" Column="1" TopLine="57"/>
       </Position17>
       <Position18>
-        <Filename Value="pkgcommands.pp"/>
-        <Caret Line="22" Column="16" TopLine="8"/>
+        <Filename Value="pkgrepos.pp"/>
+        <Caret Line="16" Column="17" TopLine="1"/>
       </Position18>
       <Position19>
-        <Filename Value="pkgcommands.pp"/>
-        <Caret Line="114" Column="43" TopLine="90"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="266" Column="30" TopLine="252"/>
       </Position19>
       <Position20>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="12" Column="1" TopLine="4"/>
+        <Filename Value="pkgcommands.pp"/>
+        <Caret Line="223" Column="1" TopLine="205"/>
       </Position20>
       <Position21>
         <Filename Value="fppkg.pp"/>
-        <Caret Line="67" Column="1" TopLine="56"/>
+        <Caret Line="278" Column="26" TopLine="260"/>
       </Position21>
       <Position22>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="113" Column="49" TopLine="99"/>
+        <Filename Value="pkgmessages.pp"/>
+        <Caret Line="65" Column="29" TopLine="41"/>
       </Position22>
       <Position23>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="211" Column="25" TopLine="197"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="36" Column="22" TopLine="29"/>
       </Position23>
       <Position24>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="55" Column="1" TopLine="27"/>
+        <Filename Value="pkgmessages.pp"/>
+        <Caret Line="65" Column="87" TopLine="43"/>
       </Position24>
       <Position25>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="9" Column="11" TopLine="1"/>
+        <Caret Line="110" Column="29" TopLine="84"/>
       </Position25>
       <Position26>
         <Filename Value="pkgrepos.pp"/>
-        <Caret Line="32" Column="16" TopLine="18"/>
+        <Caret Line="96" Column="23" TopLine="85"/>
       </Position26>
       <Position27>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="254" Column="1" TopLine="240"/>
+        <Filename Value="pkgrepos.pp"/>
+        <Caret Line="104" Column="32" TopLine="87"/>
       </Position27>
       <Position28>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="13" Column="49" TopLine="1"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="220" Column="1" TopLine="204"/>
       </Position28>
       <Position29>
-        <Filename Value="pkgarchive.pp"/>
-        <Caret Line="170" Column="26" TopLine="153"/>
+        <Filename Value="pkgrepos.pp"/>
+        <Caret Line="98" Column="19" TopLine="82"/>
       </Position29>
       <Position30>
-        <Filename Value="pkgarchive.pp"/>
-        <Caret Line="91" Column="33" TopLine="72"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="169" Column="51" TopLine="151"/>
       </Position30>
     </JumpHistory>
   </ProjectOptions>
   <CompilerOptions>
     <Version Value="5"/>
     <SearchPaths>
-      <OtherUnitFiles Value="fcl20/"/>
+      <IncludeFiles Value="lnet/sys/"/>
+      <OtherUnitFiles Value="lnet/"/>
     </SearchPaths>
     <CodeGeneration>
       <Checks>

+ 71 - 54
utils/fppkg/fppkg.pp

@@ -13,10 +13,11 @@ uses
   pkgmessages, pkgglobals, pkgoptions, pkgrepos,
   // Package Handler components
   pkghandler,pkgmkconv, pkgdownload,
-  pkgarchive, pkgfpmake, pkgcommands
+  pkgfpmake, pkgcommands
   // Downloaders
 {$if defined(unix) or defined(windows)}
   ,pkgwget
+  ,pkglnet
 {$endif}
   ;
 
@@ -25,10 +26,9 @@ Type
 
   TMakeTool = Class(TCustomApplication)
   Private
-    ActionStack : TActionStack;
-    ParaAction : string;
+    ActionStack  : TActionStack;
+    ParaAction   : string;
     ParaPackages : TStringList;
-    procedure GenerateParaActions;
     procedure MaybeCreateLocalDirs;
     procedure ShowUsage;
   Public
@@ -75,20 +75,20 @@ begin
   GeneratedConfig:=false;
   // Load file or create new default configuration
   if FileExists(cfgfile) then
-    Defaults.LoadGlobalFromFile(cfgfile)
+    GlobalOptions.LoadGlobalFromFile(cfgfile)
   else
     begin
       ForceDirectories(ExtractFilePath(cfgfile));
-      Defaults.SaveGlobalToFile(cfgfile);
+      GlobalOptions.SaveGlobalToFile(cfgfile);
       GeneratedConfig:=true;
     end;
   // Load default verbosity from config
   SL:=TStringList.Create;
-  SL.CommaText:=Defaults.DefaultVerbosity;
+  SL.CommaText:=GlobalOptions.DefaultVerbosity;
   for i:=0 to SL.Count-1 do
     Include(Verbosity,StringToVerbosity(SL[i]));
   SL.Free;
-  Defaults.CurrentCompilerConfig:=Defaults.DefaultCompilerConfig;
+  GlobalOptions.CompilerConfig:=GlobalOptions.DefaultCompilerConfig;
   // Tracing of what we've done above, need to be done after the verbosity is set
   if GeneratedConfig then
     Log(vDebug,SLogGeneratingGlobalConfig,[cfgfile])
@@ -99,9 +99,9 @@ end;
 
 procedure TMakeTool.MaybeCreateLocalDirs;
 begin
-  ForceDirectories(Defaults.BuildDir);
-  ForceDirectories(Defaults.PackagesDir);
-  ForceDirectories(Defaults.CompilerConfigDir);
+  ForceDirectories(GlobalOptions.BuildDir);
+  ForceDirectories(GlobalOptions.PackagesDir);
+  ForceDirectories(GlobalOptions.CompilerConfigDir);
 end;
 
 
@@ -109,18 +109,34 @@ procedure TMakeTool.LoadCompilerDefaults;
 var
   S : String;
 begin
-  S:=Defaults.CompilerConfigDir+Defaults.CurrentCompilerConfig;
+  // Load default compiler config
+  S:=GlobalOptions.CompilerConfigDir+GlobalOptions.CompilerConfig;
   if FileExists(S) then
     begin
       Log(vDebug,SLogLoadingCompilerConfig,[S]);
-      Defaults.LoadCompilerFromFile(S)
+      CompilerOptions.LoadCompilerFromFile(S)
     end
   else
     begin
-      Log(vDebug,SLogGeneratingCompilerConfig,[S]);
-      Defaults.InitCompilerDefaults;
-      Defaults.SaveCompilerToFile(S);
+      // Generate a default configuration if it doesn't exists
+      if GlobalOptions.CompilerConfig='default' then
+        begin
+          Log(vDebug,SLogGeneratingCompilerConfig,[S]);
+          CompilerOptions.InitCompilerDefaults;
+          CompilerOptions.SaveCompilerToFile(S);
+        end
+      else
+        Error(SErrMissingCompilerConfig,[S]);
     end;
+  // Load FPMake compiler config, this is normally the same config as above
+  S:=GlobalOptions.CompilerConfigDir+GlobalOptions.FPMakeCompilerConfig;
+  if FileExists(S) then
+    begin
+      Log(vDebug,SLogLoadingFPMakeCompilerConfig,[S]);
+      FPMakeCompilerOptions.LoadCompilerFromFile(S)
+    end
+  else
+    Error(SErrMissingCompilerConfig,[S]);
 end;
 
 
@@ -131,13 +147,18 @@ begin
   Writeln('  -c --config        Set compiler configuration to use');
   Writeln('  -h --help          This help');
   Writeln('  -v --verbose       Set verbosity');
+  Writeln('  -g --global        Force installation to global (system-wide) directory');
+  Writeln('  -f --force         Force installation also if the package is already installed');
   Writeln('Actions:');
   Writeln('  update             Update packages list');
   Writeln('  avail              List available packages');
   Writeln('  build              Build package');
+  Writeln('  compile            Compile package');
   Writeln('  install            Install package');
+  Writeln('  archive            Create archive of package');
   Writeln('  download           Download package');
   Writeln('  convertmk          Convert Makefile.fpc to fpmake.pp');
+//  Writeln('  addconfig          Add a compiler configuration for the supplied compiler');
   Halt(0);
 end;
 
@@ -207,9 +228,11 @@ begin
       Inc(I);
       // Check options.
       if CheckOption(I,'c','config') then
-        Defaults.CurrentCompilerConfig:=OptionArg(I)
+        GlobalOptions.CompilerConfig:=OptionArg(I)
       else if CheckOption(I,'v','verbose') then
         Include(Verbosity,StringToVerbosity(OptionArg(I)))
+      else if CheckOption(I,'g','global') then
+        GlobalOptions.InstallGlobal:=true
       else if CheckOption(I,'h','help') then
         begin
           ShowUsage;
@@ -234,60 +257,54 @@ begin
 end;
 
 
-procedure TMakeTool.GenerateParaActions;
-var
-  ActionPackage : TFPPackage;
-  i : integer;
-begin
-  if GetPkgHandler(ParaAction)<>nil then
-    begin
-      if ParaPackages.Count=0 then
-        begin
-          Log(vDebug,SLogCommandLineAction,['[<currentdir>]',ParaAction]);
-          ActionStack.Push(nil,ParaAction,[]);
-        end
-      else
-        begin
-          for i:=0 to ParaPackages.Count-1 do
-            begin
-              ActionPackage:=CurrentRepository.PackageByName(ParaPackages[i]);
-              Log(vDebug,SLogCommandLineAction,['['+ActionPackage.Name+']',ParaAction]);
-              ActionStack.Push(ActionPackage,ParaAction,[]);
-            end;
-        end;
-    end
-  else
-    Raise EMakeToolError.CreateFmt(SErrInvalidCommand,[ParaAction]);
-end;
-
-
 procedure TMakeTool.DoRun;
 var
-  Action : string;
   ActionPackage : TFPPackage;
-  Args   : TActionArgs;
   OldCurrDir : String;
+  Res    : Boolean;
+  i      : Integer;
 begin
   OldCurrDir:=GetCurrentDir;
-  LoadGlobalDefaults;
   Try
+    LoadGlobalDefaults;
     ProcessCommandLine;
     MaybeCreateLocalDirs;
     LoadCompilerDefaults;
+
+    // Load local repository, update first if this is a new installation
+    if not FileExists(GlobalOptions.LocalPackagesFile) then
+      pkghandler.ExecuteAction(nil,'update');
     LoadLocalRepository;
-    GenerateParaActions;
+    LoadFPMakeLocalStatus;
+    // We only need to reload the status when we use a different
+    // configuration for compiling fpmake
+    if GlobalOptions.CompilerConfig<>GlobalOptions.FPMakeCompilerConfig then
+      LoadLocalStatus;
+
+    if ParaPackages.Count=0 then
+      begin
+        Log(vDebug,SLogCommandLineAction,['[<currentdir>]',ParaAction]);
+        res:=pkghandler.ExecuteAction(nil,ParaAction);
+      end
+    else
+      begin
+        // Process packages
+        for i:=0 to ParaPackages.Count-1 do
+          begin
+            ActionPackage:=CurrentRepository.PackageByName(ParaPackages[i]);
+            Log(vDebug,SLogCommandLineAction,['['+ActionPackage.Name+']',ParaAction]);
+            res:=pkghandler.ExecuteAction(ActionPackage,ParaAction);
+            if not res then
+              break;
+          end;
+      end;
 
-    repeat
-      if not ActionStack.Pop(ActionPackage,Action,Args) then
-        break;
-      pkghandler.ExecuteAction(ActionPackage,Action,Args);
-    until false;
     Terminate;
 
   except
     On E : Exception do
       begin
-        Writeln(StdErr,SErrRunning);
+        Writeln(StdErr,SErrException);
         Writeln(StdErr,E.Message);
         Halt(1);
       end;

+ 101 - 101
utils/fppkg/fprepos.pp

@@ -26,15 +26,20 @@ Const
   StreamSignature = $FEEF;
 
 Type
-  TOS = (osNone,Amiga,Atari,Darwin,FreeBSD,Go32v2,Linux,MacOS,MorphOS,NetBSD,
-         Netware,NetwLibc,OpenBSD,OS2,PalmOS,Solaris,Win32,Win64,WinCE,Emx);
-  TOSes = Set of TOS;
-
-  TCPU = (cpuNone,Arm,I386,PPC,SPARC,X86_64,M68K,PPC64);
+  // Keep syncronized with fpmkunit.pp
+  TCpu=(cpuNone,
+    i386,m68k,powerpc,sparc,x86_64,arm,powerpc64
+  );
   TCPUS = Set of TCPU;
 
-  TCompilerMode = (cmFPC,cmTP,cmObjFPC,cmDelphi,cmMacPas);
-  TCompilerModes = Set of TCompilerMode;
+  // Keep syncronized with fpmkunit.pp
+  TOS=(osNone,
+    linux,go32v2,win32,os2,freebsd,beos,netbsd,
+    amiga,atari, solaris, qnx, netware, openbsd,wdosx,
+    palmos,macos,darwin,emx,watcom,morphos,netwlibc,
+    win64,wince,gba,nds,embedded,symbian
+  );
+  TOSes = Set of TOS;
 
   { TFPVersion }
 
@@ -48,6 +53,7 @@ Type
     function GetEmpty: Boolean;
     procedure SetAsString(const AValue: String);
   Public
+   Procedure Clear;
    Procedure Assign(Source : TPersistent); override;
    Property AsString : String Read GetAsString Write SetAsString;
    Function CompareVersion(AVersion : TFPVersion) : Integer;
@@ -85,7 +91,7 @@ Type
     function GetDependency(Index : Integer): TFPDependency;
     procedure SetDependency(Index : Integer; const AValue: TFPDependency);
   public
-    Function AddDependency(Const APackageName : String; AMinVersion : String = '') : TFPDependency;
+    Function AddDependency(const APackageName : String; const AMinVersion : String = '') : TFPDependency;
     Property Dependencies[Index : Integer] : TFPDependency Read GetDependency Write SetDependency;default;
   end;
 
@@ -145,10 +151,10 @@ Type
   Protected
     Function CurrentStreamVersion : Integer; override;
   Public
-    Function IndexOfPackage(PackageName : String) : Integer;
-    Function FindPackage(PackageName : String) : TFPPackage;
-    Function PackageByName(PackageName : String) : TFPPackage;
-    Function AddPackage(PackageName : string) : TFPPackage;
+    Function IndexOfPackage(const APackageName : String) : Integer;
+    Function FindPackage(const APackageName : String) : TFPPackage;
+    Function PackageByName(const APackageName : String) : TFPPackage;
+    Function AddPackage(const APackageName : string) : TFPPackage;
     Property StreamVersion : Integer Read FVersion Write FVersion;
     Property Packages [Index : Integer] : TFPPackage Read GetPackage Write SetPackage; default;
   end;
@@ -160,37 +166,37 @@ Type
     FMaxDependencyLevel : Integer;
     FBackUpFiles: Boolean;
     FFileName: String;
-    FPackageCount: Integer;
     FPackages : TFPPackages;
     function GetPackage(Index : Integer): TFPPackage;
     function GetPackageCount: Integer;
   Protected
     procedure CreatePackages; virtual;
-    Procedure BackupFile(AFileName : String); virtual;
-    Procedure DoGetPackageDependencies(PackageName : String; List : TStringList; Level : Integer); virtual;
+    Procedure BackupFile(const AFileName : String); virtual;
+    Procedure DoGetPackageDependencies(const APackageName : String; List : TStringList; Level : Integer); virtual;
   Public
     Constructor Create(AOwner : TComponent); override;
     Destructor Destroy; override;
     // Loading and Saving repository. Own format.
     Procedure LoadFromStream(Stream : TStream); Virtual;
     Procedure SaveToStream(Stream : TStream); Virtual;
-    Procedure LoadFromFile(AFileName : String);
-    Procedure SaveToFile(AFileName : String);
+    Procedure LoadFromFile(const AFileName : String);
+    Procedure SaveToFile(const AFileName : String);
     Procedure Save;
     // Loading and Saving version numbers: List of Name=Value pairs.
+    procedure ClearStatus;
     Procedure LoadStatusFromStream(Stream : TStream); virtual;
-    Procedure SaveStatusToStream(Stream : TStream; InstalledStatus : Boolean); virtual;
-    Procedure LoadStatusFromFile(AFileName : String);
-    Procedure SaveStatusToFile(AFileName : String; InstalledStatus : Boolean);
+    Procedure SaveStatusToStream(Stream : TStream); virtual;
+    Procedure LoadStatusFromFile(const AFileName : String);
+    Procedure SaveStatusToFile(const AFileName : String);
     // Package management
-    Function IndexOfPackage(PackageName : String) : Integer;
-    Function FindPackage(PackageName : String) : TFPPackage;
-    Function PackageByName(PackageName : String) : TFPPackage;
+    Function IndexOfPackage(const APackageName : String) : Integer;
+    Function FindPackage(const APackageName : String) : TFPPackage;
+    Function PackageByName(const APackageName : String) : TFPPackage;
     Procedure DeletePackage(Index : Integer);
-    Procedure RemovePackage(PackageName : string);
-    Function AddPackage(PackageName : string) : TFPPackage;
+    Procedure RemovePackage(const APackageName : string);
+    Function AddPackage(const APackageName : string) : TFPPackage;
     // Dependencies
-    Procedure GetPackageDependencies(PackageName : String; List : TObjectList; Recurse : Boolean);
+    Procedure GetPackageDependencies(const APackageName : String; List : TObjectList; Recurse : Boolean);
     // Properties
     Property FileName : String Read FFileName;
     Property Packages[Index : Integer] : TFPPackage Read GetPackage; default;
@@ -214,8 +220,6 @@ Function StringToOS(S : String) : TOS;
 Function OSesToString(S : String) : TOSes;
 Function StringToCPU(S : String) : TCPU;
 Function StringToCPUS(S : String) : TCPUS;
-Function ModeToString(Mode: TCompilerMode) : String;
-Function StringToMode(S : String) : TCompilerMode;
 Function MakeTargetString(CPU : TCPU;OS: TOS) : String;
 Procedure StringToCPUOS(S : String; Var CPU : TCPU; Var OS: TOS);
 
@@ -300,25 +304,6 @@ begin
   Result:=TCPUS(StringToSet(PTypeInfo(TypeInfo(TCPUS)),S));
 end;
 
-Function ModeToString(Mode: TCompilerMode) : String;
-
-begin
-  Result:=LowerCase(GetenumName(TypeInfo(TCompilerMode),Ord(Mode)));
-end;
-
-Function StringToMode(S : String) : TCompilerMode;
-
-Var
-  I : Integer;
-
-begin
-  I:=GetEnumValue(TypeInfo(TCompilerMode),S);
-  if (I=-1) then
-    Raise EPackage.CreateFmt(SErrInvalidMode,[S]);
-  Result:=TCompilerMode(I);
-end;
-
-
 Function MakeTargetString(CPU : TCPU;OS: TOS) : String;
 
 begin
@@ -343,9 +328,14 @@ end;
 
 function TFPVersion.GetAsString: String;
 begin
-  Result:=Format('%d.%d.%d',[Release,Major,Minor]);
-  If (Suffix<>'') then
-    Result:=Result+'-'+Suffix;
+  if Empty then
+    Result:='<none>'
+  else
+    begin
+      Result:=Format('%d.%d.%d',[Release,Major,Minor]);
+      If (Suffix<>'') then
+        Result:=Result+'-'+Suffix;
+    end;
 end;
 
 function TFPVersion.GetEmpty: Boolean;
@@ -376,10 +366,10 @@ Var
   V : String;
 
 begin
-  Release:=0;
-  Major:=0;
-  Minor:=0;
-  Suffix:='';
+  Clear;
+  // Special support for empty version string
+  if (AValue='') or (AValue='<none>') then
+    exit;
   V:=AValue;
   Release:=NextDigit('.',V);
   Major:=NextDigit('.',V);
@@ -390,6 +380,14 @@ begin
   Suffix:=V;
 end;
 
+procedure TFPVersion.Clear;
+begin
+  Release:=0;
+  Major:=0;
+  Minor:=0;
+  Suffix:='';
+end;
+
 procedure TFPVersion.Assign(Source: TPersistent);
 
 Var
@@ -460,9 +458,6 @@ end;
 
 procedure TFPPackage.SetName(const AValue: String);
 
-Var
-  I : Integer;
-
 begin
   If (AValue<>FName) and (AValue<>'') then
     If (Collection<>Nil) and (Collection is TFPPackages) then
@@ -482,7 +477,7 @@ end;
 
 function TFPPackage.GetHasDependencies: Boolean;
 begin
-  Result:=Assigned(FDependencies) and (FDependencies.Count>0);
+  Result:=(Dependencies<>nil) and (FDependencies.Count>0);
 end;
 
 function TFPPackage.GetFileName: String;
@@ -632,41 +627,41 @@ begin
   Result:=FVersion;
 end;
 
-function TFPPackages.IndexOfPackage(PackageName: String): Integer;
+function TFPPackages.IndexOfPackage(const APackageName: String): Integer;
 
 
 begin
   Result:=Count-1;
-  While (Result>=0) and (CompareText(GetPackage(Result).Name,PackageName)<>0) do
+  While (Result>=0) and (CompareText(GetPackage(Result).Name,APackageName)<>0) do
     Dec(Result);
 end;
 
-function TFPPackages.FindPackage(PackageName: String): TFPPackage;
+function TFPPackages.FindPackage(const APackageName: String): TFPPackage;
 
 Var
   I : Integer;
 
 begin
-  I:=IndexOfPackage(PackageName);
+  I:=IndexOfPackage(APackageName);
   If (I=-1) then
     Result:=Nil
   else
     Result:=GetPackage(I);
 end;
 
-function TFPPackages.PackageByName(PackageName: String): TFPPackage;
+function TFPPackages.PackageByName(const APackageName: String): TFPPackage;
 begin
-  Result:=FindPackage(PackageName);
+  Result:=FindPackage(APackageName);
   If Result=Nil then
-    Raise EPackage.CreateFmt(SErrPackageNotFound,[PackageName]);
+    Raise EPackage.CreateFmt(SErrPackageNotFound,[APackageName]);
 end;
 
-function TFPPackages.AddPackage(PackageName: string): TFPPackage;
+function TFPPackages.AddPackage(const APackageName: string): TFPPackage;
 
 begin
   Result:=Add as TFPPackage;
   Try
-    Result.Name:=PackageName;
+    Result.Name:=APackageName;
   Except
     Result.Free;
     Raise;
@@ -701,7 +696,7 @@ begin
   FPackages.StreamVersion:=StreamVersion;
 end;
 
-procedure TFPRepository.BackupFile(AFileName: String);
+procedure TFPRepository.BackupFile(const AFileName: String);
 
 Var
   S : String;
@@ -747,7 +742,7 @@ begin
   FPackages.SaveToStream(Stream);
 end;
 
-procedure TFPRepository.LoadFromFile(AFileName: String);
+procedure TFPRepository.LoadFromFile(const AFileName: String);
 
 Var
   F : TFileStream;
@@ -762,11 +757,10 @@ begin
   end;
 end;
 
-procedure TFPRepository.SaveToFile(AFileName: String);
+procedure TFPRepository.SaveToFile(const AFileName: String);
 
 Var
   F : TFileStream;
-  S : String;
 
 begin
   If FileExists(AFileName) and BackupFiles then
@@ -787,6 +781,17 @@ begin
   SaveToFile(FFileName);
 end;
 
+
+procedure TFPRepository.ClearStatus;
+Var
+  I : Integer;
+begin
+  For I:=0 to PackageCount-1 do
+    With Packages[i] do
+      InstalledVersion.Clear;
+end;
+
+
 procedure TFPRepository.LoadStatusFromStream(Stream: TStream);
 
 Var
@@ -809,7 +814,7 @@ begin
   end;
 end;
 
-procedure TFPRepository.SaveStatusToStream(Stream: TStream;InstalledStatus : Boolean);
+procedure TFPRepository.SaveStatusToStream(Stream: TStream);
 
 Var
   L : TStrings;
@@ -818,21 +823,17 @@ Var
 begin
   L:=TStringList.Create;
   Try
-    If InstalledStatus then
-      For I:=0 to PackageCount-1 do
-        With Packages[i] do
-          L.Add(Name+'='+InstalledVersion.AsString)
-    else
-      For I:=0 to PackageCount-1 do
-        With Packages[i] do
-         L.Add(Name+'='+Version.AsString);
+    For I:=0 to PackageCount-1 do
+      With Packages[i] do
+        if not InstalledVersion.Empty then
+          L.Add(Name+'='+InstalledVersion.AsString);
     L.SaveToStream(Stream);
   Finally
     L.Free;
   end;
 end;
 
-procedure TFPRepository.LoadStatusFromFile(AFileName: String);
+procedure TFPRepository.LoadStatusFromFile(const AFileName: String);
 
 Var
   F : TFileStream;
@@ -846,7 +847,7 @@ begin
   end;
 end;
 
-procedure TFPRepository.SaveStatusToFile(AFileName: String; InstalledStatus : Boolean);
+procedure TFPRepository.SaveStatusToFile(const AFileName: String);
 
 Var
   F : TFileStream;
@@ -856,30 +857,30 @@ begin
     BackupFile(AFileName);
   F:=TFileStream.Create(AFileName,fmCreate);
   Try
-    SaveStatusToStream(F,InstalledStatus);
+    SaveStatusToStream(F);
   Finally
     F.Free;
   end;
 end;
 
-function TFPRepository.IndexOfPackage(PackageName: String): Integer;
+function TFPRepository.IndexOfPackage(const APackageName: String): Integer;
 begin
-  Result:=FPackages.IndexOfPackage(PackageName);
+  Result:=FPackages.IndexOfPackage(APackageName);
 end;
 
-function TFPRepository.FindPackage(PackageName: String): TFPPackage;
+function TFPRepository.FindPackage(const APackageName: String): TFPPackage;
 begin
-  Result:=FPackages.FindPackage(PackageName);
+  Result:=FPackages.FindPackage(APackageName);
 end;
 
-function TFPRepository.PackageByName(PackageName: String): TFPPackage;
+function TFPRepository.PackageByName(const APackageName: String): TFPPackage;
 begin
-  Result:=FPackages.PackageByName(PackageName);
+  Result:=FPackages.PackageByName(APackageName);
 end;
 
-procedure TFPRepository.RemovePackage(PackageName: string);
+procedure TFPRepository.RemovePackage(const APackageName: string);
 begin
-  PackageByName(PackageName).Free;
+  PackageByName(APackageName).Free;
 end;
 
 procedure TFPRepository.DeletePackage(Index : Integer);
@@ -887,13 +888,13 @@ begin
   GetPackage(Index).Free;
 end;
 
-function TFPRepository.AddPackage(PackageName: string): TFPPackage;
+function TFPRepository.AddPackage(const APackageName: string): TFPPackage;
 
 begin
-  Result:=FPackages.AddPackage(PackageName);
+  Result:=FPackages.AddPackage(APackageName);
 end;
 
-procedure TFPRepository.DoGetPackageDependencies(PackageName: String;
+procedure TFPRepository.DoGetPackageDependencies(const APackageName: String;
   List: TStringList; Level: Integer);
 Var
   P : TFPPackage;
@@ -903,14 +904,14 @@ Var
 begin
   // If too many levels, bail out
   If (Level>FMaxDependencyLevel) then
-    Raise EPackage.CreateFmt(SErrMaxLevelExceeded,[Level,PackageName]);
+    Raise EPackage.CreateFmt(SErrMaxLevelExceeded,[Level,APackageName]);
   // Check if it is a known package.
-  P:=FindPackage(PackageName);
+  P:=FindPackage(APackageName);
   If Assigned(P) and P.HasDependencies then
     For I:=0 to P.Dependencies.Count-1 do
       begin
       D1:=P.Dependencies[i];
-      J:=List.IndexOf(PackageName);
+      J:=List.IndexOf(APackageName);
       If J=-1 then
         begin
         // Dependency not yet in list.
@@ -931,7 +932,7 @@ begin
       end;
 end;
 
-procedure TFPRepository.GetPackageDependencies(PackageName: String;
+procedure TFPRepository.GetPackageDependencies(const APackageName: String;
   List: TObjectList; Recurse: Boolean);
 
 Var
@@ -942,7 +943,7 @@ begin
   L:=TStringList.Create;
   Try
     L.Sorted:=True;
-    DoGetPackageDependencies(PackageName,L,Ord(Recurse)-1);
+    DoGetPackageDependencies(APackageName,L,Ord(Recurse)-1);
     For I:=0 to L.Count-1 do
       List.Add(L.Objects[i]);
   Finally
@@ -1009,8 +1010,7 @@ begin
   Items[Index]:=AValue;
 end;
 
-function TFPDependencies.AddDependency(const APackageName: String;
-  AMinVersion: String): TFPDependency;
+function TFPDependencies.AddDependency(const APackageName: String; const AMinVersion: String): TFPDependency;
 begin
   Result:=Add as TFPDependency;
   Result.PackageName:=APackageName;

+ 5 - 1
utils/fppkg/lnet/lcommon.pp

@@ -1,6 +1,6 @@
 { lCommon
 
-  CopyRight (C) 2004-2006 Ales Katona
+  CopyRight (C) 2004-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -62,6 +62,10 @@ const
         LMSG = 0;
       {$ENDIF}
     {$ENDIF}
+    
+    {$IFDEF DARWIN}
+    SO_NOSIGPIPE = $1022; // for fpc 2.0.4
+    {$ENDIF}
   {$ENDIF}
   { Default Values }
   LDEFAULT_BACKLOG = 5;

+ 1 - 1
utils/fppkg/lnet/lcontrolstack.pp

@@ -1,6 +1,6 @@
 { Control stack
 
-  CopyRight (C) 2004-2006 Ales Katona
+  CopyRight (C) 2004-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 10 - 1
utils/fppkg/lnet/levents.pp

@@ -1,6 +1,6 @@
 { lNet Events abstration
 
-  CopyRight (C) 2006 Ales Katona
+  CopyRight (C) 2006-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -158,6 +158,7 @@ type
     function CallAction: Boolean; virtual;
     procedure RemoveHandle(aHandle: TLHandle); virtual;
     procedure UnplugHandle(aHandle: TLHandle); virtual;
+    procedure UnregisterHandle(aHandle: TLHandle); virtual;
     procedure LoadFromEventer(aEventer: TLEventer); virtual;
     procedure Clear;
     procedure AddRef;
@@ -424,6 +425,11 @@ begin
   end;
 end;
 
+procedure TLEventer.UnregisterHandle(aHandle: TLHandle);
+begin
+  // do nothing, specific to win32 LCLEventer crap (windows is shit)
+end;
+
 procedure TLEventer.LoadFromEventer(aEventer: TLEventer);
 begin
   Clear;
@@ -499,6 +505,9 @@ var
   MaxHandle, n: Integer;
   TempTime: TTimeVal;
 begin
+  if FInLoop then
+    Exit;
+
   if not Assigned(FRoot) then begin
     Sleep(FTimeout.tv_sec * 1000 + FTimeout.tv_usec div 1000);
     Exit;

+ 1 - 1
utils/fppkg/lnet/lfastcgi.pp

@@ -1,6 +1,6 @@
 { FastCGI requester support for lNet
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 6 - 6
utils/fppkg/lnet/lftp.pp

@@ -1,4 +1,4 @@
-{ lFTP CopyRight (C) 2005-2006 Ales Katona
+{ lFTP CopyRight (C) 2005-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -70,8 +70,8 @@ type
 
     function GetConnected: Boolean; virtual;
     
-    function GetTimeout: DWord;
-    procedure SetTimeout(const Value: DWord);
+    function GetTimeout: Integer;
+    procedure SetTimeout(const Value: Integer);
     
     function GetSocketClass: TLSocketClass;
     procedure SetSocketClass(Value: TLSocketClass);
@@ -87,7 +87,7 @@ type
     
    public
     property Connected: Boolean read GetConnected;
-    property Timeout: DWord read GetTimeout write SetTimeout;
+    property Timeout: Integer read GetTimeout write SetTimeout;
     property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
     property ControlConnection: TLTelnetClient read FControl;
     property DataConnection: TLTCP read FData;
@@ -280,12 +280,12 @@ begin
   Result := FControl.Connected;
 end;
 
-function TLFTP.GetTimeout: DWord;
+function TLFTP.GetTimeout: Integer;
 begin
   Result := FControl.Timeout;
 end;
 
-procedure TLFTP.SetTimeout(const Value: DWord);
+procedure TLFTP.SetTimeout(const Value: Integer);
 begin
   FControl.Timeout := Value;
   FData.Timeout := Value;

+ 1 - 1
utils/fppkg/lnet/lhttp.pp

@@ -1,6 +1,6 @@
 { HTTP server and client components
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 1 - 4
utils/fppkg/lnet/lhttputil.pp

@@ -1,6 +1,6 @@
 { Utility routines for HTTP server component
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -244,9 +244,6 @@ begin
   if index > 0 then begin
     Port := StrToIntDef(Copy(Host, index+1, Length(Host)-index), -1);
 
-    if (Port < 0) or (Port > 65535) then
-      Port := 80;
-
     SetLength(Host, index-1);
   end else
     Port := 80;

+ 23 - 0
utils/fppkg/lnet/lmimestreams.pp

@@ -1,3 +1,26 @@
+{ MIME Streams
+
+  CopyRight (C) 2006-2007 Micha Nelissen
+
+  This library is Free software; you can rediStribute it and/or modify it
+  under the terms of the GNU Library General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version.
+
+  This program is diStributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+  for more details.
+
+  You should have received a Copy of the GNU Library General Public License
+  along with This library; if not, Write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  This license has been modified. See File LICENSE.ADDON for more inFormation.
+  Should you find these sources without a LICENSE File, please contact
+  me at [email protected]
+}
+
 unit lMimeStreams;
 
 {$mode objfpc}{$H+}

+ 1 - 1
utils/fppkg/lnet/lmimetypes.pp

@@ -1,6 +1,6 @@
 { Mime types helper
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 37 - 6
utils/fppkg/lnet/lmimewrapper.pp

@@ -1,3 +1,26 @@
+{ lNet MIME Wrapper
+
+  CopyRight (C) 2007 Ales Katona
+
+  This library is Free software; you can rediStribute it and/or modify it
+  under the terms of the GNU Library General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version.
+
+  This program is diStributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+  for more details.
+
+  You should have received a Copy of the GNU Library General Public License
+  along with This library; if not, Write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  This license has been modified. See File LICENSE.ADDON for more inFormation.
+  Should you find these sources without a LICENSE File, please contact
+  me at [email protected]
+}
+
 unit lMimeWrapper;
 
 {$mode objfpc}{$H+}
@@ -115,9 +138,9 @@ type
     function GetSize: Int64; override;
     function GetCount: Integer;
     function GetBoundary: string;
-    function GetSections(i: Integer): TMimeSection;
+    function GetSection(i: Integer): TMimeSection;
     function GetMimeHeader: string;
-    procedure SetSections(i: Integer; const AValue: TMimeSection);
+    procedure SetSection(i: Integer; const AValue: TMimeSection);
     procedure ActivateFirstSection;
     procedure ActivateNextSection;
     procedure DoRead(const aSize: Integer);
@@ -135,7 +158,7 @@ type
     procedure Remove(aSection: TMimeSection);
     procedure Reset;
    public
-    property Sections[i: Integer]: TMimeSection read GetSections write SetSections; default;
+    property Sections[i: Integer]: TMimeSection read GetSection write SetSection; default;
     property Count: Integer read GetCount;
     property Boundary: string read FBoundary;
   end;
@@ -529,7 +552,7 @@ begin
     Result := Result + Char(Random(Ord('9') - Ord('0') + 1) + Ord('0'));
 end;
 
-function TMimeStream.GetSections(i: Integer): TMimeSection;
+function TMimeStream.GetSection(i: Integer): TMimeSection;
 begin
   Result := nil;
   
@@ -550,7 +573,7 @@ begin
          '--' + FBoundary + CRLF;
 end;
 
-procedure TMimeStream.SetSections(i: Integer; const AValue: TMimeSection);
+procedure TMimeStream.SetSection(i: Integer; const AValue: TMimeSection);
 begin
   if  (i >= 0)
   and (i < FSections.Count) then
@@ -740,9 +763,17 @@ begin
   or (s = 'cpp')
   or (s = 'cc')
   or (s = 'h')
+  or (s = 'hh')
+  or (s = 'rb')
+  or (s = 'pod')
+  or (s = 'php')
+  or (s = 'php3')
+  or (s = 'php4')
+  or (s = 'php5')
   or (s = 'c++') then FContentType := 'text/plain';
   
-  if s = 'html' then FContentType := 'text/html';
+  if (s = 'html')
+  or (s = 'shtml') then FContentType := 'text/html';
   if s = 'css' then FContentType := 'text/css';
   
   if s = 'png' then FContentType := 'image/x-png';

+ 64 - 16
utils/fppkg/lnet/lnet.pp

@@ -1,6 +1,6 @@
-{ lNet v0.5.6
+{ lNet v0.5.8
 
-  CopyRight (C) 2004-2006 Ales Katona
+  CopyRight (C) 2004-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -91,6 +91,7 @@ type
    protected
     FAddress: TInetSockAddr;
     FPeerAddress: TInetSockAddr;
+    FReuseAddress: Boolean;
     FConnected: Boolean;
     FConnecting: Boolean;
     FNextSock: TLSocket;
@@ -117,9 +118,10 @@ type
     function CanSend: Boolean; virtual;
     function CanReceive: Boolean; virtual;
     
-    procedure SetBlocking(const aValue: Boolean);
     procedure SetOptions; virtual;
-    
+    procedure SetBlocking(const aValue: Boolean);
+    procedure SetReuseAddress(const aValue: Boolean);
+
     function Bail(const msg: string; const ernum: Integer): Boolean;
     
     procedure LogError(const msg: string; const ernum: Integer); virtual;
@@ -150,6 +152,7 @@ type
     property PeerPort: Word read GetPeerPort;
     property LocalAddress: string read GetLocalAddress;
     property LocalPort: Word read GetLocalPort;
+    property ReuseAddress: Boolean read FReuseAddress write SetReuseAddress;
     property NextSock: TLSocket read FNextSock write FNextSock;
     property PrevSock: TLSocket read FPrevSock write FPrevSock;
     property Creator: TLComponent read FCreator;
@@ -230,7 +233,7 @@ type
     FID: Integer; // internal number for server
     FEventer: TLEventer;
     FEventerClass: TLEventerClass;
-    FTimeout: DWord;
+    FTimeout: Integer;
     FListenBacklog: Integer;
    protected
     function InitSocket(aSocket: TLSocket): TLSocket; virtual;
@@ -239,8 +242,8 @@ type
     function GetCount: Integer; virtual;
     function GetItem(const i: Integer): TLSocket;
     
-    function GetTimeout: DWord;
-    procedure SetTimeout(const AValue: DWord);
+    function GetTimeout: Integer;
+    procedure SetTimeout(const AValue: Integer);
     
     procedure SetEventer(Value: TLEventer);
     
@@ -289,7 +292,7 @@ type
     property Connected: Boolean read GetConnected;
     property ListenBacklog: Integer read FListenBacklog write FListenBacklog;
     property Iterator: TLSocket read FIterator;
-    property Timeout: DWord read GetTimeout write SetTimeout;
+    property Timeout: Integer read GetTimeout write SetTimeout;
     property Eventer: TLEventer read FEventer write SetEventer;
     property EventerClass: TLEventerClass read FEventerClass write FEventerClass;
   end;
@@ -341,12 +344,15 @@ type
   TLTcp = class(TLConnection)
    protected
     FCount: Integer;
+    FReuseAddress: Boolean;
     function InitSocket(aSocket: TLSocket): TLSocket; override;
 
     function GetConnected: Boolean; override;
     function GetConnecting: Boolean;
     function GetCount: Integer; override;
 
+    procedure SetReuseAddress(const aValue: Boolean);
+
     procedure ConnectAction(aSocket: TLHandle); override;
     procedure AcceptAction(aSocket: TLHandle); override;
     procedure ReceiveAction(aSocket: TLHandle); override;
@@ -378,6 +384,7 @@ type
     property Connecting: Boolean read GetConnecting;
     property OnAccept: TLSocketEvent read FOnAccept write FOnAccept;
     property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
+    property ReuseAddress: Boolean read FReuseAddress write SetReuseAddress;
   end;
   
 implementation
@@ -429,6 +436,10 @@ begin
     if (FSocketType = SOCK_STREAM) and (not FIgnoreShutdown) and WasConnected then
       if fpShutDown(FHandle, 2) <> 0 then
         LogError('Shutdown error', LSocketError);
+        
+    if Assigned(FEventer) then
+      FEventer.UnregisterHandle(Self);
+        
     if CloseSocket(FHandle) <> 0 then
       LogError('Closesocket error', LSocketError);
     FHandle := INVALID_SOCKET;
@@ -482,6 +493,11 @@ begin
   Result := FCanReceive and FConnected;
 end;
 
+procedure TLSocket.SetOptions;
+begin
+  SetBlocking(FBlocking);
+end;
+
 procedure TLSocket.SetBlocking(const aValue: Boolean);
 begin
   FBlocking := aValue;
@@ -490,9 +506,10 @@ begin
       Bail('Error on SetBlocking', LSocketError);
 end;
 
-procedure TLSocket.SetOptions;
+procedure TLSocket.SetReuseAddress(const aValue: Boolean);
 begin
-  SetBlocking(FBlocking);
+  if not FConnected then
+    FReuseAddress := aValue;
 end;
 
 function TLSocket.GetMessage(out msg: string): Integer;
@@ -514,8 +531,13 @@ begin
       Result := sockets.fpRecv(FHandle, @aData, aSize, LMSG)
     else
       Result := sockets.fpRecvfrom(FHandle, @aData, aSize, LMSG, @FPeerAddress, @AddressLength);
+      
     if Result = 0 then
-      Disconnect;
+      if FSocketType = SOCK_STREAM then
+        Disconnect
+      else
+        Bail('Receive Error [0 on recvfrom with UDP]', 0);
+      
     if Result = SOCKET_ERROR then begin
       LastError := LSocketError;
       if IsBlockError(LastError) then begin
@@ -542,7 +564,7 @@ end;
 function TLSocket.SetupSocket(const APort: Word; const Address: string): Boolean;
 var
   Done: Boolean;
-  Arg: Integer;
+  Arg, Opt: Integer;
 begin
   Result := false;
   if not FConnected and not FConnecting then begin
@@ -551,12 +573,27 @@ begin
     if FHandle = INVALID_SOCKET then
       Exit(Bail('Socket error', LSocketError));
     SetOptions;
+
+    Arg := 1;
     if FSocketType = SOCK_DGRAM then begin
-      Arg := 1;
       if fpsetsockopt(FHandle, SOL_SOCKET, SO_BROADCAST, @Arg, Sizeof(Arg)) = SOCKET_ERROR then
         Exit(Bail('SetSockOpt error', LSocketError));
+    end else if FReuseAddress then begin
+      Opt := SO_REUSEADDR;
+      {$ifdef WIN32} // I expect 64 has it oddly, so screw them for now
+      if (Win32Platform = 2) and (Win32MajorVersion >= 5) then
+        Opt := Integer(not Opt);
+      {$endif}
+      if fpsetsockopt(FHandle, SOL_SOCKET, Opt, @Arg, Sizeof(Arg)) = SOCKET_ERROR then
+        Exit(Bail('SetSockOpt error', LSocketError));
     end;
     
+    {$ifdef darwin}
+    Arg := 1;
+    if fpsetsockopt(FHandle, SOL_SOCKET, SO_NOSIGPIPE, @Arg, Sizeof(Arg)) = SOCKET_ERROR then
+      Exit(Bail('SetSockOpt error', LSocketError));
+    {$endif}
+    
     FillAddressInfo(FAddress, AF_INET, Address, aPort);
     FillAddressInfo(FPeerAddress, AF_INET, LADDR_BR, aPort);
 
@@ -730,7 +767,7 @@ begin
     Result := Tmp;
 end;
 
-function TLConnection.GetTimeout: DWord;
+function TLConnection.GetTimeout: Integer;
 begin
   if Assigned(FEventer) then
     Result := FEventer.Timeout
@@ -794,7 +831,7 @@ begin
     FOnError(msg, TLSocket(aSocket));
 end;
 
-procedure TLConnection.SetTimeout(const AValue: DWord);
+procedure TLConnection.SetTimeout(const AValue: Integer);
 begin
   if Assigned(FEventer) then
     FEventer.Timeout := aValue;
@@ -824,7 +861,7 @@ begin
   if Assigned(FRootSock) then
     FEventer.AddHandle(FRootSock);
 
-  if (FEventer.Timeout = 0) and (FTimeout > 0) then
+  if (FEventer.Timeout = 0) and (FTimeout <> 0) then
     FEventer.Timeout := FTimeout
   else
     FTimeout := FEventer.Timeout;
@@ -838,6 +875,7 @@ begin
   while Assigned(Tmp) do begin
     Tmp2 := Tmp;
     Tmp := Tmp.NextSock;
+    Tmp2.Disconnect;
     Tmp2.Free;
   end;
 end;
@@ -1062,10 +1100,12 @@ begin
   
   FRootSock := InitSocket(SocketClass.Create);
   FRootSock.FIgnoreShutdown := True;
+  FRootSock.SetReuseAddress(FReuseAddress);
   if FRootSock.Listen(APort, AIntf) then begin
     FRootSock.FConnected := True;
     FRootSock.FServerSocket := True;
     FIterator := FRootSock;
+    Inc(FCount);
     RegisterWithEventer;
     Result := true;
   end;
@@ -1100,6 +1140,7 @@ begin
     aSocket.PrevSock.NextSock := aSocket.NextSock;
   if Assigned(aSocket.NextSock) then
     aSocket.NextSock.PrevSock := aSocket.PrevSock;
+    
   Dec(FCount);
 end;
 
@@ -1240,6 +1281,13 @@ begin
   Result := FCount;
 end;
 
+procedure TLTcp.SetReuseAddress(const aValue: Boolean);
+begin
+  if not Assigned(FRootSock)
+  or not FRootSock.Connected then
+    FReuseAddress := aValue;
+end;
+
 function TLTcp.Get(var aData; const aSize: Integer; aSocket: TLSocket): Integer;
 begin
   Result := 0;

+ 1 - 1
utils/fppkg/lnet/lprocess.pp

@@ -1,6 +1,6 @@
 { Asynchronous process support
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 91 - 143
utils/fppkg/lnet/lsmtp.pp

@@ -1,6 +1,6 @@
 { lNet SMTP unit
 
-  CopyRight (C) 2005-2006 Ales Katona
+  CopyRight (C) 2005-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -29,7 +29,7 @@ unit lsmtp;
 interface
 
 uses
-  Classes, Contnrs, lNet, lEvents, lCommon;
+  Classes, SysUtils, Contnrs, lNet, lEvents, lCommon, lMimeWrapper, lMimeStreams;
   
 type
   TLSMTP = class;
@@ -53,69 +53,41 @@ type
   TLSMTPClientStatusEvent = procedure (aSocket: TLSocket;
                                        const aStatus: TLSMTPStatus) of object;
                                        
-  { TAttachment }
-
-  TAttachment = class
-   protected
-    FData: TStringList;
-    function GetAsText: string; virtual;
-   public
-    constructor Create;
-    destructor Destroy; override;
-    function LoadFromFile(const aFileName: string): Boolean;
-   public
-    property AsText: string read GetAsText;
-  end;
-  
-  { TAttachmentList }
-
-  TAttachmentList = class
-   protected
-    FItems: TFPObjectList;
-    function GetCount: Integer;
-    function GetItem(i: Integer): TAttachment;
-    procedure SetItem(i: Integer; const AValue: TAttachment);
-   public
-    constructor Create;
-    destructor Destroy; override;
-    function Add(anAttachment: TAttachment): Integer;
-    function AddFromFile(const aFileName: string): Integer;
-    function Remove(anAttachment: TAttachment): Integer;
-    procedure Delete(const i: Integer);
-    procedure Clear;
-   public
-    property Count: Integer read GetCount;
-    property Items[i: Integer]: TAttachment read GetItem write SetItem; default;
-  end;
-
   { TMail }
 
   TMail = class
    protected
     FMailText: string;
-    FMailStream: TStream;
+    FMailStream: TMimeStream;
     FRecipients: string;
     FSender: string;
     FSubject: string;
-    FAttachments: TAttachmentList;
+    function GetCount: Integer;
+    function GetSection(i: Integer): TMimeSection;
+    procedure SetSection(i: Integer; const AValue: TMimeSection);
    public
     constructor Create;
     destructor Destroy; override;
+    procedure AddTextSection(const aText: string; const aCharSet: string = 'UTF-8');
+    procedure AddFileSection(const aFileName: string);
+    procedure AddStreamSection(aStream: TStream; const FreeStream: Boolean = False);
+    procedure DeleteSection(const i: Integer);
+    procedure RemoveSection(aSection: TMimeSection);
    public
-    property Attachments: TAttachmentList read FAttachments;
-    property MailText: string read FMailText write FMailText;
-    property MailStream: TStream read FMailStream write FMailStream;
+    property MailText: string read FMailText write FMailText; deprecated; // use sections!
     property Sender: string read FSender write FSender;
     property Recipients: string read FRecipients write FRecipients;
     property Subject: string read FSubject write FSubject;
+    property Sections[i: Integer]: TMimeSection read GetSection write SetSection; default;
+    property SectionCount: Integer read GetCount;
   end;
 
   TLSMTP = class(TLComponent)
    protected
     FConnection: TLTcp;
    protected
-    function GetTimeout: DWord;
-    procedure SetTimeout(const AValue: DWord);
+    function GetTimeout: Integer;
+    procedure SetTimeout(const AValue: Integer);
     
     function GetConnected: Boolean;
 
@@ -133,7 +105,7 @@ type
 
     property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
     property Eventer: TLEventer read GetEventer write SetEventer;
-    property Timeout: DWord read GetTimeout write SetTimeout;
+    property Timeout: Integer read GetTimeout write SetTimeout;
   end;
 
   { TLSMTPClient }
@@ -155,6 +127,8 @@ type
     FSL: TStringList;
     FStatusSet: TLSMTPStatusSet;
     FBuffer: string;
+    FDataBuffer: string; // intermediate wait buffer on DATA command
+    FCharCount: Integer; // count of chars from last CRLF
     FStream: TStream;
    protected
     procedure OnEr(const msg: string; aSocket: TLSocket);
@@ -171,7 +145,7 @@ type
     
     procedure ExecuteFrontCommand;
     
-    procedure InsertCRLFs;
+    procedure ClearCR_LF;
     procedure SendData(const FromStream: Boolean = False);
    public
     constructor Create(aOwner: TComponent); override;
@@ -212,9 +186,6 @@ type
 
 implementation
 
-uses
-  SysUtils, lMimeStreams;
-
 const
   EMPTY_REC: TLSMTPStatusRec = (Status: ssNone; Args: ('', ''));
 
@@ -237,12 +208,12 @@ end;
 
 { TLSMTP }
 
-function TLSMTP.GetTimeout: DWord;
+function TLSMTP.GetTimeout: Integer;
 begin
   Result := FConnection.Timeout;
 end;
 
-procedure TLSMTP.SetTimeout(const AValue: DWord);
+procedure TLSMTP.SetTimeout(const AValue: Integer);
 begin
   FConnection.Timeout := aValue;
 end;
@@ -431,8 +402,13 @@ begin
                             Eventize(FStatus.First.Status, True);
                             FStatus.Remove;
                           end;
-                300..399: SendData(True);
+                300..399: begin
+                            FBuffer := FDataBuffer;
+                            FDataBuffer := '';
+                            SendData(True);
+                          end;
               else        begin
+                            FDataBuffer := '';
                             Eventize(FStatus.First.Status, False);
                             FStatus.Remove;
                           end;
@@ -471,26 +447,39 @@ begin
   FCommandFront.Remove;
 end;
 
-procedure TLSMTPClient.InsertCRLFs;
+procedure TLSMTPClient.ClearCR_LF;
 var
-  i, c: Integer;
-begin
-  c := 0;
-  i := 2;
-  while i <= Length(FBuffer) do begin
-    if (FBuffer[i - 1] = #13) and (FBuffer[i] = #10) then begin
-      c := 0;
-      Inc(i);
-    end else
-      Inc(c);
-      
-    if c >= 74 then begin
-      Insert(CRLF, FBuffer, i);
-      c := 0;
-      Inc(i, 2);
+  i: Integer;
+  Skip: Boolean = False;
+begin
+  for i := 1 to Length(FBuffer) do begin
+    if Skip then begin
+      Skip := False;
+      Continue;
     end;
-
-    Inc(i);
+    
+    if (FBuffer[i] = #13) or (FBuffer[i] = #10) then begin
+      if FBuffer[i] = #13 then
+        if (i < Length(FBuffer)) and (FBuffer[i + 1] = #10) then begin
+          FCharCount := 0;
+          Skip := True; // skip the crlf
+        end else begin // insert LF to a standalone CR
+          System.Insert(#10, FBuffer, i + 1);
+          FCharCount := 0;
+          Skip := True; // skip the new crlf
+        end;
+        
+      if FBuffer[i] = #10 then begin
+        System.Insert(#13, FBuffer, i);
+        FCharCount := 0;
+        Skip := True; // skip the new crlf
+      end;
+    end else if FCharCount >= 1000 then begin // line too long
+      System.Insert(CRLF, FBuffer, i);
+      FCharCount := 0;
+      Skip := True;
+    end else
+      Inc(FCharCount);
   end;
 end;
 
@@ -523,7 +512,7 @@ begin
   n := 1;
   Sent := 0;
   while (Length(FBuffer) > 0) and (n > 0) do begin
-    InsertCRLFs;
+    ClearCR_LF;
   
     n := FConnection.SendMessage(FBuffer);
     Sent := Sent + n;
@@ -615,10 +604,10 @@ end;
 
 procedure TLSMTPClient.SendMail(aMail: TMail);
 begin
-  if Length(aMail.MailText) > 0 then
-    SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.MailText)
-  else if Assigned(aMail.MailStream) then
-    SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.MailStream);
+  if Length(aMail.FMailText) > 0 then
+    SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.FMailText)
+  else if Assigned(aMail.FMailStream) then
+    SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.FMailStream);
 end;
 
 procedure TLSMTPClient.Helo(aHost: string = '');
@@ -664,16 +653,17 @@ end;
 procedure TLSMTPClient.Data(const Msg: string);
 begin
   if CanContinue(ssData, Msg, '') then begin
+    FBuffer := 'DATA ' + CRLF;
+    FDataBuffer := '';
+
     if Assigned(FStream) then begin
       if Length(Msg) > 0 then
-        FBuffer := 'DATA ' + Msg
-      else
-        FBuffer := 'DATA ';
+        FDataBuffer := Msg;
     end else
-      FBuffer := 'DATA ' + Msg + CRLF + '.' + CRLF;
-      
+      FDataBuffer := Msg + CRLF + '.' + CRLF;
+
     FStatus.Insert(MakeStatusRec(ssData, '', ''));
-    SendData(True);
+    SendData(False);
   end;
 end;
 
@@ -709,98 +699,56 @@ end;
 
 { TMail }
 
-constructor TMail.Create;
+function TMail.GetCount: Integer;
 begin
-
-end;
-
-destructor TMail.Destroy;
-begin
-
+  Result := FMailStream.Count;
 end;
 
-{ TAttachment }
-
-function TAttachment.GetAsText: string;
+function TMail.GetSection(i: Integer): TMimeSection;
 begin
-  Result := '';
-  raise Exception.Create('Not yet implemented');
+  Result := FMailStream.Sections[i];
 end;
 
-constructor TAttachment.Create;
+procedure TMail.SetSection(i: Integer; const AValue: TMimeSection);
 begin
-  FData := TStringList.Create;
-end;
-
-destructor TAttachment.Destroy;
-begin
-  FData.Free;
-  inherited Destroy;
-end;
-
-function TAttachment.LoadFromFile(const aFileName: string): Boolean;
-begin
-  Result := False;
-  raise Exception.Create('Not yet implemented');
+  FMailStream.Sections[i] := aValue;
 end;
 
-{ TAttachmentList }
-
-function TAttachmentList.GetCount: Integer;
-begin
-  Result := FItems.Count;
-end;
-
-function TAttachmentList.GetItem(i: Integer): TAttachment;
-begin
-  Result := TAttachment(FItems[i]);
-end;
-
-procedure TAttachmentList.SetItem(i: Integer; const AValue: TAttachment);
+constructor TMail.Create;
 begin
-  FItems[i] := aValue;
+  FMailStream := TMimeStream.Create;
 end;
 
-constructor TAttachmentList.Create;
+destructor TMail.Destroy;
 begin
-  FItems := TFPObjectList.Create(True);
+  FMailStream.Free;
 end;
 
-destructor TAttachmentList.Destroy;
+procedure TMail.AddTextSection(const aText: string; const aCharSet: string);
 begin
-  FItems.Free;
-  inherited Destroy;
+  FMailStream.AddTextSection(aText, aCharSet);
 end;
 
-function TAttachmentList.Add(anAttachment: TAttachment): Integer;
+procedure TMail.AddFileSection(const aFileName: string);
 begin
-  Result := FItems.Add(anAttachment);
+  FMailStream.AddFileSection(aFileName);
 end;
 
-function TAttachmentList.AddFromFile(const aFileName: string): Integer;
-var
-  Tmp: TAttachment;
+procedure TMail.AddStreamSection(aStream: TStream; const FreeStream: Boolean);
 begin
-  Tmp := TAttachment.Create;
-  
-  if Tmp.LoadFromFile(aFileName) then
-    Result := FItems.Add(Tmp);
+  FMailStream.AddStreamSection(aStream, FreeStream);
 end;
 
-function TAttachmentList.Remove(anAttachment: TAttachment): Integer;
+procedure TMail.DeleteSection(const i: Integer);
 begin
-  Result := FItems.Remove(anAttachment);
+  FMailStream.Delete(i);
 end;
 
-procedure TAttachmentList.Delete(const i: Integer);
+procedure TMail.RemoveSection(aSection: TMimeSection);
 begin
-  FItems.Delete(i);
+  FMailStream.Remove(aSection);
 end;
 
-procedure TAttachmentList.Clear;
-begin
-  FItems.Clear;
-end;
 
 end.
 

+ 23 - 0
utils/fppkg/lnet/lspawnfcgi.pp

@@ -1,3 +1,26 @@
+{ lNet FastCGI Spawner
+
+  CopyRight (C) 2006-2007 Ales Katona
+
+  This library is Free software; you can rediStribute it and/or modify it
+  under the terms of the GNU Library General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version.
+
+  This program is diStributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+  for more details.
+
+  You should have received a Copy of the GNU Library General Public License
+  along with This library; if not, Write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  This license has been modified. See File LICENSE.ADDON for more inFormation.
+  Should you find these sources without a LICENSE File, please contact
+  me at [email protected]
+}
+
 unit lSpawnFCGI;
 
 {$mode objfpc}{$H+}

+ 1 - 1
utils/fppkg/lnet/lstrbuffer.pp

@@ -1,6 +1,6 @@
 { Efficient string buffer helper
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 6 - 6
utils/fppkg/lnet/ltelnet.pp

@@ -1,4 +1,4 @@
-{ lTelnet CopyRight (C) 2004-2006 Ales Katona
+{ lTelnet CopyRight (C) 2004-2007 Ales Katona
 
   This library is Free software; you can rediStribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
@@ -91,8 +91,8 @@ type
 
     function Question(const Command: Char; const Value: Boolean): Char;
     
-    function GetTimeout: DWord;
-    procedure SetTimeout(const Value: DWord);
+    function GetTimeout: Integer;
+    procedure SetTimeout(const Value: Integer);
 
     function GetSocketClass: TLSocketClass;
     procedure SetSocketClass(Value: TLSocketClass);
@@ -129,7 +129,7 @@ type
    public
     property Output: TMemoryStream read FOutput;
     property Connected: Boolean read FConnected;
-    property Timeout: DWord read GetTimeout write SetTimeout;
+    property Timeout: Integer read GetTimeout write SetTimeout;
     property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
     property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
     property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
@@ -222,7 +222,7 @@ begin
   Result := FConnection.SocketClass;
 end;
 
-function TLTelnet.GetTimeout: DWord;
+function TLTelnet.GetTimeout: Integer;
 begin
   Result := FConnection.Timeout;
 end;
@@ -232,7 +232,7 @@ begin
   FConnection.SocketClass := Value;
 end;
 
-procedure TLTelnet.SetTimeout(const Value: DWord);
+procedure TLTelnet.SetTimeout(const Value: Integer);
 begin
   FConnection.Timeout := Value;
 end;

+ 23 - 0
utils/fppkg/lnet/ltimer.pp

@@ -1,3 +1,26 @@
+{ lNet Timer
+
+  CopyRight (C) 2006-2007 Micha Nelissen
+
+  This library is Free software; you can rediStribute it and/or modify it
+  under the terms of the GNU Library General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version.
+
+  This program is diStributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+  for more details.
+
+  You should have received a Copy of the GNU Library General Public License
+  along with This library; if not, Write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  This license has been modified. See File LICENSE.ADDON for more inFormation.
+  Should you find these sources without a LICENSE File, please contact
+  me at [email protected]
+}
+
 unit ltimer;
 
 {$mode objfpc}{$H+}

+ 1 - 1
utils/fppkg/lnet/lwebserver.pp

@@ -1,6 +1,6 @@
 { Web server component, built on the HTTP server component
 
-  Copyright (C) 2006 Micha Nelissen
+  Copyright (C) 2006-2007 Micha Nelissen
 
   This library is Free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by

+ 3 - 0
utils/fppkg/lnet/sys/lepolleventer.inc

@@ -126,6 +126,9 @@ var
   MasterEvents: array[0..1] of TEpollEvent;
 begin
   Result := False;
+  if FInLoop then
+    Exit;
+    
   Changes := 0;
   ReadChanges := 0;
 

+ 4 - 0
utils/fppkg/lnet/sys/lkqueueeventer.inc

@@ -90,6 +90,10 @@ var
   i, n: Integer;
   Temp: TLHandle;
 begin
+  Result := False;
+  if FInLoop then
+    Exit;
+
   if FTimeout.tv_sec >= 0 then
     n := KEvent(FQueue, @FChanges[0], FFreeSlot,
               @FEvents[0], Length(FEvents), @FTimeout)

+ 0 - 137
utils/fppkg/pkgarchive.pp

@@ -1,137 +0,0 @@
-unit pkgarchive;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
-  Classes,SysUtils,pkghandler;
-
-type
-  { TUnzipArchive }
-
-  TUnzipArchive = Class(TPackagehandler)
-  Private
-    Procedure UnzipArchive;
-  Public
-    Function Execute(const Args:TActionArgs):boolean;override;
-  end;
-
-
-  { TCreateArchive }
-
-  TCreateArchive = Class(TPackagehandler)
-  Private
-    Procedure CreateArchive;
-  Public
-    Function Execute(const Args:TActionArgs):boolean;override;
-  end;
-
-
-implementation
-
-uses
-  fprepos,
-  fpxmlrep,
-  zipper,
-  uriparser,
-  pkgglobals,
-  pkgmessages;
-
-{ TUnzipArchive }
-
-Procedure TUnzipArchive.UnzipArchive;
-Var
-  BuildDir : string;
-  ArchiveFile : String;
-begin
-  ArchiveFile:=PackageLocalArchive;
-  BuildDir:=PackageBuildPath;
-  { Download file if it doesn't exists yet }
-  if not FileExists(ArchiveFile) then
-    ExecuteAction(CurrentPackage,'downloadpackage');
-  { Create builddir, remove it first if needed }
-  if DirectoryExists(BuildDir) then
-    DeleteDir(BuildDir);
-  ForceDirectories(BuildDir);
-  SetCurrentDir(BuildDir);
-  { Unzip Archive }
-  With TUnZipper.Create do
-    try
-      Log(vCommands,SLogUnzippping,[ArchiveFile]);
-      OutputPath:=PackageBuildPath;
-      UnZipAllFiles(ArchiveFile);
-    Finally
-      Free;
-    end;
-end;
-
-
-function TUnzipArchive.Execute(const Args:TActionArgs):boolean;
-begin
-{$warning TODO Check arguments}
-  UnzipArchive;
-  result:=true;
-end;
-
-
-{ TCreateArchive }
-
-procedure TCreateArchive.CreateArchive;
-var
-  P : TFPPackage;
-  PS : TFPPackages;
-  X : TFPXMLRepositoryHandler;
-  SL : TStringList;
-begin
-  if assigned(CurrentPackage) then
-    Error(SErrOnlyLocalDir);
-  { Generate manifest.xml if it doesn't exists yet }
-  if not FileExists(PackageManifestFile) then
-    ExecuteAction(CurrentPackage,'fpmakemanifest');
-  { Load manifest.xml }
-  PS:=TFPPackages.Create(TFPPackage);
-  X:=TFPXMLRepositoryHandler.Create;
-  With X do
-    try
-      LoadFromXml(PS,PackageManifestFile);
-    finally
-      Free;
-    end;
-  { Create archive, currently support only 1 file per package, this
-    can be enhanced in the future if needed }
-  if PS.Count<>1 then
-    Error('Only one package supported per manifest');
-  P:=PS[0];
-  { Unzip Archive }
-  With TZipper.Create do
-    try
-      Log(vCommands,SLogZippping,[P.FileName]);
-{$warning TODO replace with files from manifest}
-      try
-        SL:=TStringList.Create;
-        SearchFiles(SL,AllFiles);
-        if SL.Count=0 then
-          Error('No files found');
-        ZipFiles(P.FileName,SL);
-      finally
-        SL.Free;
-      end;
-    Finally
-      Free;
-    end;
-  P.Free;
-end;
-
-
-function TCreateArchive.Execute(const Args: TActionArgs): boolean;
-begin
-  CreateArchive;
-  Result:=true;
-end;
-
-
-initialization
-  RegisterPkgHandler('unziparchive',TUnzipArchive);
-  RegisterPkgHandler('createarchive',TCreateArchive);
-end.

+ 175 - 17
utils/fppkg/pkgcommands.pp

@@ -7,7 +7,25 @@ interface
 uses
   Classes, SysUtils,pkghandler;
 
+implementation
+
+uses
+  zipper,
+  pkgmessages,
+  pkgglobals,
+  pkgoptions,
+  pkgdownload,
+  pkgrepos,
+  fprepos;
+
 type
+  { TCommandAddConfig }
+
+  TCommandAddConfig = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
   { TCommandUpdate }
 
   TCommandUpdate = Class(TPackagehandler)
@@ -15,6 +33,13 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
+  { TCommandAllAvail }
+
+  TCommandAllAvail = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
   { TCommandAvail }
 
   TCommandAvail = Class(TPackagehandler)
@@ -43,6 +68,13 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
+  { TCommandCompile }
+
+  TCommandCompile = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
   { TCommandBuild }
 
   TCommandBuild = Class(TPackagehandler)
@@ -50,7 +82,6 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
-
   { TCommandInstall }
 
   TCommandInstall = Class(TPackagehandler)
@@ -58,34 +89,63 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
+  { TCommandArchive }
 
-implementation
+  TCommandArchive = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
+  { TCommandInstallDependencies }
+
+  TCommandInstallDependencies = Class(TPackagehandler)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
+
+function TCommandAddConfig.Execute(const Args:TActionArgs):boolean;
+begin
+{
+  Log(vInfo,SLogGeneratingCompilerConfig,[S]);
+  Options.InitCompilerDefaults(Args[2]);
+  Options.SaveCompilerToFile(S);
+}
+  Result:=true;
+end;
 
-uses
-  pkgmessages,
-  pkgglobals,
-  pkgoptions,
-  pkgdownload,
-  pkgrepos;
 
 function TCommandUpdate.Execute(const Args:TActionArgs):boolean;
 begin
-  DownloadFile(Defaults.RemotePackagesFile,Defaults.LocalPackagesFile);
+  Log(vCommands,SLogDownloading,[GlobalOptions.RemotePackagesFile,GlobalOptions.LocalPackagesFile]);
+  DownloadFile(GlobalOptions.RemotePackagesFile,GlobalOptions.LocalPackagesFile);
+  // Read the repository again
   LoadLocalRepository;
+  LoadLocalStatus;
+  Result:=true;
+end;
+
+
+function TCommandAllAvail.Execute(const Args:TActionArgs):boolean;
+begin
+  ListLocalRepository(true);
+  Result:=true;
 end;
 
 
 function TCommandAvail.Execute(const Args:TActionArgs):boolean;
 begin
-  ListRepository;
+  ListLocalRepository(false);
+  Result:=true;
 end;
 
 
 function TCommandScanPackages.Execute(const Args:TActionArgs):boolean;
 begin
-  RebuildRepository;
-  ListRepository;
-  SaveRepository;
+  RebuildRemoteRepository;
+  ListRemoteRepository;
+  SaveRemoteRepository;
+  Result:=true;
 end;
 
 
@@ -95,14 +155,48 @@ begin
     Error(SErrNoPackageSpecified);
   if not FileExists(PackageLocalArchive) then
     ExecuteAction(CurrentPackage,'downloadpackage',Args);
+  Result:=true;
 end;
 
 
 function TCommandUnzip.Execute(const Args:TActionArgs):boolean;
+Var
+  BuildDir : string;
+  ArchiveFile : String;
 begin
+  BuildDir:=PackageBuildPath;
+  ArchiveFile:=PackageLocalArchive;
   if not assigned(CurrentPackage) then
     Error(SErrNoPackageSpecified);
-  ExecuteAction(CurrentPackage,'unziparchive',Args);
+  if not FileExists(ArchiveFile) then
+    ExecuteAction(CurrentPackage,'downloadpackage');
+  { Create builddir, remove it first if needed }
+  if DirectoryExists(BuildDir) then
+    DeleteDir(BuildDir);
+  ForceDirectories(BuildDir);
+  SetCurrentDir(BuildDir);
+  { Unzip Archive }
+  With TUnZipper.Create do
+    try
+      Log(vCommands,SLogUnzippping,[ArchiveFile]);
+      OutputPath:=PackageBuildPath;
+      UnZipAllFiles(ArchiveFile);
+    Finally
+      Free;
+    end;
+  Result:=true;
+end;
+
+
+function TCommandCompile.Execute(const Args:TActionArgs):boolean;
+begin
+  if assigned(CurrentPackage) then
+    begin
+      ExecuteAction(CurrentPackage,'installdependencies',Args);
+      ExecuteAction(CurrentPackage,'unzip',Args);
+    end;
+  ExecuteAction(CurrentPackage,'fpmakecompile',Args);
+  Result:=true;
 end;
 
 
@@ -110,26 +204,90 @@ function TCommandBuild.Execute(const Args:TActionArgs):boolean;
 begin
   if assigned(CurrentPackage) then
     begin
-      if not DirectoryExists(PackageBuildPath) then
-        ExecuteAction(CurrentPackage,'unziparchive',Args);
+      ExecuteAction(CurrentPackage,'installdependencies',Args);
+      ExecuteAction(CurrentPackage,'unzip',Args);
     end;
   ExecuteAction(CurrentPackage,'fpmakebuild',Args);
+  Result:=true;
 end;
 
 
 function TCommandInstall.Execute(const Args:TActionArgs):boolean;
 begin
-  ExecuteAction(CurrentPackage,'build',Args);
+  if assigned(CurrentPackage) then
+    ExecuteAction(CurrentPackage,'build',Args);
   ExecuteAction(CurrentPackage,'fpmakeinstall',Args);
+  // Update local status file
+  if assigned(CurrentPackage) then
+    begin
+      CurrentPackage.InstalledVersion.Assign(CurrentPackage.Version);
+      SaveLocalStatus;
+    end;
+  Result:=true;
+end;
+
+
+function TCommandArchive.Execute(const Args:TActionArgs):boolean;
+begin
+  ExecuteAction(CurrentPackage,'fpmakearchive',Args);
+  Result:=true;
+end;
+
+
+function TCommandInstallDependencies.Execute(const Args:TActionArgs):boolean;
+var
+  i : Integer;
+  D : TFPDependency;
+  DepPackage : TFPPackage;
+  L : TStringList;
+  status : string;
+begin
+  if not assigned(CurrentPackage) then
+    Error(SErrNoPackageSpecified);
+  // List dependencies
+  L:=TStringList.Create;
+  for i:=0 to CurrentPackage.Dependencies.Count-1 do
+    begin
+      D:=CurrentPackage.Dependencies[i];
+      DepPackage:=CurrentRepository.PackageByName(D.PackageName);
+      // Need installation?
+      if (DepPackage.InstalledVersion.Empty) or
+         (DepPackage.InstalledVersion.CompareVersion(D.MinVersion)<0) then
+        begin
+          if DepPackage.Version.CompareVersion(D.MinVersion)<0 then
+            status:='Not Available!'
+          else
+            status:='Updating';
+          L.Add(DepPackage.Name);
+        end
+      else
+        status:='OK';
+      Log(vDebug,SDbgPackageDependency,
+          [D.PackageName,D.MinVersion.AsString,DepPackage.InstalledVersion.AsString,DepPackage.Version.AsString,status]);
+    end;
+  // Install needed updates
+  for i:=0 to L.Count-1 do
+    begin
+      DepPackage:=CurrentRepository.PackageByName(L[i]);
+      if DepPackage.Version.CompareVersion(D.MinVersion)<0 then
+        Error(SErrNoPackageAvailable,[D.PackageName,D.MinVersion.AsString]);
+      ExecuteAction(DepPackage,'install');
+    end;
+  FreeAndNil(L);
+  Result:=true;
 end;
 
 
 initialization
   RegisterPkgHandler('update',TCommandUpdate);
+  RegisterPkgHandler('allavail',TCommandAllAvail);
   RegisterPkgHandler('avail',TCommandAvail);
   RegisterPkgHandler('scan',TCommandScanPackages);
   RegisterPkgHandler('download',TCommandDownload);
   RegisterPkgHandler('unzip',TCommandUnzip);
+  RegisterPkgHandler('compile',TCommandCompile);
   RegisterPkgHandler('build',TCommandBuild);
   RegisterPkgHandler('install',TCommandInstall);
+  RegisterPkgHandler('archive',TCommandArchive);
+  RegisterPkgHandler('installdependencies',TCommandInstallDependencies);
 end.

+ 47 - 22
utils/fppkg/pkgdownload.pp

@@ -1,4 +1,4 @@
-unit pkgdownload;
+unit pkgDownload;
 
 {$mode objfpc}{$H+}
 
@@ -15,7 +15,6 @@ Type
   Private
     FBackupFile : Boolean;
   Protected
-    Procedure BackupFile(Const FileName : String);
     // Needs overriding.
     Procedure FTPDownload(Const URL : String; Dest : TStream); Virtual;
     Procedure HTTPDownload(Const URL : String; Dest : TStream); Virtual;
@@ -34,8 +33,8 @@ Type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
-Var
-  DownloaderClass : TBaseDownloaderClass;
+procedure RegisterDownloader(const AName:string;Downloaderclass:TBaseDownloaderClass);
+function GetDownloader(const AName:string):TBaseDownloaderClass;
 
 procedure DownloadFile(const RemoteFile,LocalFile:String);
 
@@ -43,13 +42,39 @@ procedure DownloadFile(const RemoteFile,LocalFile:String);
 implementation
 
 uses
+  contnrs,
   uriparser,
   pkgglobals,
+  pkgoptions,
   pkgmessages;
 
+var
+  DownloaderList  : TFPHashList;
+
+procedure RegisterDownloader(const AName:string;Downloaderclass:TBaseDownloaderClass);
+begin
+  if DownloaderList.Find(AName)<>nil then
+    begin
+      Error('Downloader already registered');
+      exit;
+    end;
+  DownloaderList.Add(AName,Downloaderclass);
+end;
+
+
+function GetDownloader(const AName:string):TBaseDownloaderClass;
+begin
+  result:=TBaseDownloaderClass(DownloaderList.Find(AName));
+  if result=nil then
+    Error('Downloader %s not supported',[AName]);
+end;
+
 
 procedure DownloadFile(const RemoteFile,LocalFile:String);
+var
+  DownloaderClass : TBaseDownloaderClass;
 begin
+  DownloaderClass:=GetDownloader(GlobalOptions.Downloader);
   with DownloaderClass.Create(nil) do
     try
       Download(RemoteFile,LocalFile);
@@ -61,15 +86,6 @@ end;
 
 { TBaseDownloader }
 
-procedure TBaseDownloader.BackupFile(const FileName: String);
-Var
-  BFN : String;
-begin
-  BFN:=FileName+'.bak';
-  If not RenameFile(FileName,BFN) then
-    Error(SErrBackupFailed,[FileName,BFN]);
-end;
-
 procedure TBaseDownloader.FTPDownload(const URL: String; Dest: TStream);
 begin
   Error(SErrNoFTPDownload);
@@ -104,14 +120,18 @@ Var
   F : TFileStream;
 
 begin
-  Log(vCommands,SLogDownloading,[URL,DestFileName]);
   If FileExists(DestFileName) and BackupFiles then
     BackupFile(DestFileName);
-  F:=TFileStream.Create(DestFileName,fmCreate);
-  Try
-    Download(URL,F);
-  Finally
-    F.Free;
+  try
+    F:=TFileStream.Create(DestFileName,fmCreate);
+    try
+      Download(URL,F);
+    finally
+      F.Free;
+    end;
+  except
+    DeleteFile(DestFileName);
+    raise;
   end;
 end;
 
@@ -138,9 +158,13 @@ end;
 { TDownloadPackage }
 
 function TDownloadPackage.Execute(const Args:TActionArgs):boolean;
+var
+  DownloaderClass : TBaseDownloaderClass;
 begin
+  DownloaderClass:=GetDownloader(GlobalOptions.Downloader);
   with DownloaderClass.Create(nil) do
     try
+      Log(vCommands,SLogDownloading,[PackageRemoteArchive,PackageLocalArchive]);
       Download(PackageRemoteArchive,PackageLocalArchive);
     finally
       Free;
@@ -149,9 +173,10 @@ end;
 
 
 initialization
-  // Default value.
-  DownloaderClass := TBaseDownloader;
-
+  DownloaderList:=TFPHashList.Create;
+  RegisterDownloader('base',TBaseDownloader);
   RegisterPkgHandler('downloadpackage',TDownloadPackage);
+finalization
+  FreeAndNil(DownloaderList);
 end.
 

+ 166 - 28
utils/fppkg/pkgfpmake.pp

@@ -7,6 +7,14 @@ interface
 uses
   Classes, SysUtils,pkghandler;
 
+implementation
+
+uses
+  fprepos,
+  pkgoptions,
+  pkgglobals,
+  pkgmessages;
+
 type
   { TFPMakeCompiler }
 
@@ -26,6 +34,14 @@ type
   end;
 
 
+  { TFPMakeRunnerCompile }
+
+  TFPMakeRunnerCompile = Class(TFPMakeRunner)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
+
   { TFPMakeRunnerBuild }
 
   TFPMakeRunnerBuild = Class(TFPMakeRunner)
@@ -49,27 +65,90 @@ type
     Function Execute(const Args:TActionArgs):boolean;override;
   end;
 
+  { TFPMakeRunnerArchive }
 
-implementation
+  TFPMakeRunnerArchive = Class(TFPMakeRunner)
+  Public
+    Function Execute(const Args:TActionArgs):boolean;override;
+  end;
+
+   TMyMemoryStream=class(TMemoryStream)
+   public
+     constructor Create(p:pointer;mysize:integer);
+   end;
+
+{$i fpmkunitsrc.inc}
+
+procedure CreateFPMKUnitSource(const AFileName:string);
+var
+  InStream,
+  OutStream : TStream;
+  pend      : pchar;
+begin
+  try
+    // Don't write trailing #0
+    pend:=pchar(@fpmkunitsrc)+sizeof(fpmkunitsrc)-1;
+    while pend^=#0 do
+      dec(pend);
+    InStream:=TMyMemoryStream.Create(@fpmkunitsrc,pend-pchar(@fpmkunitsrc));
+    OutStream:=TFileStream.Create(AFileName,fmCreate);
+    OutStream.CopyFrom(InStream,InStream.Size);
+  finally
+    InStream.Destroy;
+    OutStream.Destroy;
+  end;
+end;
+
+
+{*****************************************************************************
+                               TMyMemoryStream
+*****************************************************************************}
+
+    constructor TMyMemoryStream.Create(p:pointer;mysize:integer);
+      begin
+        inherited Create;
+        SetPointer(p,mysize);
+      end;
 
-uses
-  pkgoptions,
-  pkgglobals,
-  pkgmessages;
 
 { TFPMakeCompiler }
 
 Procedure TFPMakeCompiler.CompileFPMake;
+
+  function CheckUnitDir(const AUnitName:string;Out AUnitDir:string):boolean;
+  begin
+    Result:=false;
+    if FPMakeCompilerOptions.LocalUnitDir<>'' then
+      begin
+        AUnitDir:=IncludeTrailingPathDelimiter(FPMakeCompilerOptions.LocalUnitDir+AUnitName);
+        if DirectoryExistsLog(AUnitDir) then
+          begin
+            Result:=true;
+            exit;
+          end;
+      end;
+    AUnitDir:=IncludeTrailingPathDelimiter(FPMakeCompilerOptions.GlobalUnitDir+AUnitName);
+    if DirectoryExistsLog(AUnitDir) then
+      begin
+        Result:=true;
+        exit;
+      end;
+    AUnitDir:='';
+  end;
+
+const
+  TempBuildDir = 'build-fpmake';
 Var
-  O,C : String;
-  RTLDir,
-  FPPkgDir,
+  i : Integer;
+  OOptions,
+  DepDir,
   FPMakeBin,
   FPMakeSrc : string;
+  NeedFPMKUnitSource,
   HaveFpmake : boolean;
 begin
   SetCurrentDir(PackageBuildPath);
-  { Check for fpmake source }
+  // Check for fpmake source
   FPMakeBin:='fpmake'+ExeExt;
   FPMakeSrc:='fpmake.pp';
   HaveFpmake:=FileExists(FPMakeSrc);
@@ -79,27 +158,56 @@ begin
       If HaveFPMake then
         FPMakeSrc:='fpmake.pas';
     end;
-  { Need to compile fpmake executable? }
+  // Need to compile fpmake executable?
   if not FileExists(FPMakeBin) or
      (FileAge(FPMakeBin)<FileAge(FPMakeSrc)) then
     begin
       if Not HaveFPMake then
         Error(SErrMissingFPMake);
-      { Detect installed units directories }
-      if not DirectoryExists(Defaults.FPMakeUnitDir) then
-        Error(SErrMissingDirectory,[Defaults.FPMakeUnitDir]);
-      RTLDir:=Defaults.FPMakeUnitDir+'..'+PathDelim+'rtl'+PathDelim;
-      if not DirectoryExists(RTLDir) then
-        Error(SErrMissingDirectory,[RTLDir]);
-      FPPkgDir:=Defaults.FPMakeUnitDir+'..'+PathDelim+'fppkg'+PathDelim;
-      if not DirectoryExists(FPPkgDir) then
-        FPPkgDir:='';
-      { Call compiler }
-      C:=Defaults.FPMakeCompiler;
-      O:='-vi -n -Fu'+Defaults.FPMakeUnitDir+' -Fu'+RTLDir;
-      O:=O+' '+FPmakeSrc;
-      If ExecuteProcess(C,O)<>0 then
-        Error(SErrFailedToCompileFPCMake)
+      OOptions:='-n';
+      for i:=1 to FPMKUnitDepCount do
+        begin
+          if FPMKUnitDepAvailable[i] then
+            begin
+              if CheckUnitDir(FPMKUnitDeps[i].package,DepDir) then
+                OOptions:=OOptions+' -Fu'+DepDir
+              else
+                Error(SErrMissingInstallPackage,[FPMKUnitDeps[i].package]);
+            end
+          else
+            begin
+              // If fpmkunit is not installed, we use the internal fpmkunit source
+              if FPMKUnitDeps[i].package='fpmkunit' then
+                begin
+                  NeedFPMKUnitSource:=true;
+                  OOptions:=OOptions+' -Fu'+TempBuildDir;
+                end;
+              if FPMKUnitDeps[i].undef<>'' then
+                OOptions:=OOptions+' -d'+FPMKUnitDeps[i].undef;
+            end;
+        end;
+      // Add RTL unit dir
+      if not CheckUnitDir('rtl',DepDir) then
+        Error(SErrMissingInstallPackage,['rtl']);
+      OOptions:=OOptions+' -Fu'+DepDir;
+      // Units in a directory for easy cleaning
+      DeleteDir(TempBuildDir);
+      ForceDirectories(TempBuildDir);
+      OOptions:=OOptions+' -FU'+TempBuildDir;
+      // Compile options
+      //   -- default is to optimize, smartlink and strip to reduce
+      //      the executable size (there can be 100's of fpmake's on a system)
+      if vInfo in Verbosity then
+        OOptions:=OOptions+' -vi';
+      OOptions:=OOptions+' -O2 -XXs';
+      // Create fpmkunit.pp if needed
+      if NeedFPMKUnitSource then
+        CreateFPMKUnitSource(TempBuildDir+PathDelim+'fpmkunit.pp');
+      // Call compiler
+      If ExecuteProcess(FPMakeCompilerOptions.Compiler,OOptions+' '+FPmakeSrc)<>0 then
+        Error(SErrFailedToCompileFPCMake);
+      // Cleanup units
+      DeleteDir(TempBuildDir);
     end
   else
     Log(vCommands,SLogNotCompilingFPMake);
@@ -118,14 +226,37 @@ end;
 
 Function TFPMakeRunner.RunFPMake(const Command:string) : Integer;
 Var
-  FPMakeBin : string;
+  FPMakeBin,
+  OOptions : string;
 begin
   { Maybe compile fpmake executable? }
   ExecuteAction(CurrentPackage,'compilefpmake');
+  { Create options }
+  OOptions:=' --nofpccfg';
+  if vInfo in Verbosity then
+    OOptions:=OOptions+' --verbose';
+  OOptions:=OOptions+' --compiler='+CompilerOptions.Compiler;
+  OOptions:=OOptions+' --CPU='+CPUToString(CompilerOptions.CompilerCPU);
+  OOptions:=OOptions+' --OS='+OSToString(CompilerOptions.CompilerOS);
+  if IsSuperUser or GlobalOptions.InstallGlobal then
+    OOptions:=OOptions+' --baseinstalldir='+CompilerOptions.GlobalInstallDir
+  else
+    OOptions:=OOptions+' --baseinstalldir='+CompilerOptions.LocalInstallDir;
+  if CompilerOptions.LocalInstallDir<>'' then
+    OOptions:=OOptions+' --localunitdir='+CompilerOptions.LocalUnitDir;
+  OOptions:=OOptions+' --globalunitdir='+CompilerOptions.GlobalUnitDir;
   { Run FPMake }
   FPMakeBin:='fpmake'+ExeExt;
   SetCurrentDir(PackageBuildPath);
-  Result:=ExecuteProcess(FPMakeBin,Command);
+  Result:=ExecuteProcess(FPMakeBin,Command+OOptions);
+  if Result<>0 then
+    Error(SErrExecutionFPMake,[Command]);
+end;
+
+
+function TFPMakeRunnerCompile.Execute(const Args:TActionArgs):boolean;
+begin
+  result:=(RunFPMake('compile')=0);
 end;
 
 
@@ -135,7 +266,6 @@ begin
 end;
 
 
-
 function TFPMakeRunnerInstall.Execute(const Args:TActionArgs):boolean;
 begin
   result:=(RunFPMake('install')=0);
@@ -148,11 +278,19 @@ begin
 end;
 
 
+function TFPMakeRunnerArchive.Execute(const Args:TActionArgs):boolean;
+begin
+  result:=(RunFPMake('archive')=0);
+end;
+
+
 
 
 initialization
   RegisterPkgHandler('compilefpmake',TFPMakeCompiler);
+  RegisterPkgHandler('fpmakecompile',TFPMakeRunnerCompile);
   RegisterPkgHandler('fpmakebuild',TFPMakeRunnerBuild);
   RegisterPkgHandler('fpmakeinstall',TFPMakeRunnerInstall);
   RegisterPkgHandler('fpmakemanifest',TFPMakeRunnerManifest);
+  RegisterPkgHandler('fpmakearchive',TFPMakeRunnerArchive);
 end.

+ 95 - 11
utils/fppkg/pkgglobals.pp

@@ -17,6 +17,31 @@ Const
   AllFiles='*.*';
 {$endif unix}
 
+Type
+  TFPMKUnitDep=record
+    package : string[12];
+    reqver  : string[8];
+    undef   : string[16];
+  end;
+
+Const
+  // Dependencies for compiling the fpmkunit unit
+  FPMKUnitDepCount=4;
+  FPMKUnitDeps : array[1..4] of TFPMKUnitDep = (
+    (package: 'hash';
+     reqver : '2.0.0';
+     undef  : 'NO_UNIT_ZIPPER'),
+    (package: 'paszlib';
+     reqver : '2.2.0';
+     undef  : 'NO_UNIT_ZIPPER'),
+    (package: 'fcl-process';
+     reqver : '2.0.0';
+     undef  : 'NO_UNIT_PROCESS'),
+    (package: 'fpmkunit';
+     reqver : '2.2.0';
+     undef  : '')
+  );
+
 Type
   TVerbosity = (vError,vWarning,vInfo,vCommands,vDebug);
   TVerbosities = Set of TVerbosity;
@@ -34,32 +59,33 @@ Procedure Error(Fmt : String; const Args : array of const);
 // Utils
 function maybequoted(const s:string):string;
 Function FixPath(const S : String) : string;
+Function DirectoryExistsLog(const ADir:string):Boolean;
+Function FileExistsLog(const AFileName:string):Boolean;
+procedure BackupFile(const AFileName: String);
 Procedure DeleteDir(const ADir:string);
 Procedure SearchFiles(SL:TStringList;const APattern:string);
 Function GetCompilerInfo(const ACompiler,AOptions:string):string;
+function IsSuperUser:boolean;
 
 var
   Verbosity : TVerbosities;
+  FPMKUnitDepAvailable : array[1..FPMKUnitDepCount] of boolean;
 
 
 Implementation
 
 // define use_shell to use sysutils.executeprocess
 //  as alternate to using 'process' in getcompilerinfo
-{$IFDEF GO32v2}
+{$IF defined(GO32v2) or defined(WATCOM) or defined(OS2)}
  {$DEFINE USE_SHELL}
-{$ENDIF GO32v2}
+{$ENDIF GO32v2 or WATCOM or OS2}
 
-{$IFDEF WATCOM}
- {$DEFINE USE_SHELL}
-{$ENDIF WATCOM}
-
-{$IFDEF OS2}
- {$DEFINE USE_SHELL}
-{$ENDIF OS2}
 
 uses
   typinfo,
+{$ifdef unix}
+  baseunix,
+{$endif}
 {$IFNDEF USE_SHELL}
   process,
 {$ENDIF USE_SHELL}
@@ -67,6 +93,7 @@ uses
   uriparser,
   pkgmessages;
 
+
 function StringToVerbosity(S: String): TVerbosity;
 Var
   I : integer;
@@ -78,6 +105,7 @@ begin
     Raise EPackagerError.CreateFmt(SErrInvalidVerbosity,[S]);
 end;
 
+
 Function VerbosityToString (V : TVerbosity): String;
 begin
   Result:=GetEnumName(TypeInfo(TVerbosity),Integer(V));
@@ -92,8 +120,18 @@ begin
   if not(Level in Verbosity) then
     exit;
   Prefix:='';
-  if Level=vWarning then
-    Prefix:=SWarning;
+  case Level of
+    vWarning :
+      Prefix:=SWarning;
+    vError :
+      Prefix:=SError;
+{    vInfo :
+      Prefix:='I: ';
+    vCommands :
+      Prefix:='C: ';
+    vDebug :
+      Prefix:='D: '; }
+  end;
   Writeln(stdErr,Prefix,Msg);
 end;
 
@@ -169,10 +207,44 @@ begin
 end;
 
 
+Function DirectoryExistsLog(const ADir:string):Boolean;
+begin
+  result:=SysUtils.DirectoryExists(ADir);
+  if result then
+    Log(vDebug,SDbgDirectoryExists,[ADir,SDbgFound])
+  else
+    Log(vDebug,SDbgDirectoryExists,[ADir,SDbgNotFound]);
+end;
+
+
+Function FileExistsLog(const AFileName:string):Boolean;
+begin
+  result:=SysUtils.FileExists(AFileName);
+  if result then
+    Log(vDebug,SDbgFileExists,[AFileName,SDbgFound])
+  else
+    Log(vDebug,SDbgFileExists,[AFileName,SDbgNotFound]);
+end;
+
+
+procedure BackupFile(const AFileName: String);
+Var
+  BFN : String;
+begin
+  BFN:=AFileName+'.bak';
+  Log(vDebug,SDbgBackupFile,[BFN]);
+  If not RenameFile(AFileName,BFN) then
+    Error(SErrBackupFailed,[AFileName,BFN]);
+end;
+
+
 Procedure DeleteDir(const ADir:string);
 var
   Info : TSearchRec;
 begin
+  // Prevent accidently deleting all files in current or root dir
+  if (ADir='') or (ADir=PathDelim) then
+    exit;
   if FindFirst(ADir+PathDelim+AllFiles,faAnyFile, Info)=0 then
     try
       repeat
@@ -187,6 +259,7 @@ begin
     finally
       FindClose(Info);
     end;
+  RemoveDir(Adir);
 end;
 
 
@@ -254,4 +327,15 @@ begin
   Move(Buf,Result[1],Count);
 end;
 
+
+function IsSuperUser:boolean;
+begin
+{$ifdef unix}
+  result:=(fpGetUID=0);
+{$else unix}
+  result:=true;
+{$endif unix}
+end;
+
+
 end.

+ 29 - 9
utils/fppkg/pkghandler.pp

@@ -64,7 +64,7 @@ type
 // Actions/PkgHandler
 procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
 function GetPkgHandler(const AAction:string):TPackageHandlerClass;
-procedure ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil);
+function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
 
 
 Implementation
@@ -76,7 +76,8 @@ uses
   pkgmessages;
 
 var
-  PkgHandlerList : TFPHashList;
+  PkgHandlerList  : TFPHashList;
+  ExecutedActions : TFPHashList;
 
 procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
 begin
@@ -97,12 +98,27 @@ begin
 end;
 
 
-procedure ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil);
+function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
 var
   pkghandlerclass : TPackageHandlerClass;
   i : integer;
   logargs : string;
+  FullActionName : string;
 begin
+  result:=false;
+  // Check if we have already executed or are executing the action
+  if assigned(Apackage) then
+    FullActionName:=APackage.Name+AAction
+  else
+    FullActionName:=AAction;
+  if ExecutedActions.Find(FullActionName)<>nil then
+    begin
+      Log(vDebug,'Already executed or executing action '+FullActionName);
+      result:=true;
+      exit;
+    end;
+  ExecutedActions.Add(FullActionName,Pointer(PtrUInt(1)));
+  // Create action handler class
   pkghandlerclass:=GetPkgHandler(AAction);
   With pkghandlerclass.Create(nil,APackage) do
     try
@@ -114,8 +130,9 @@ begin
           else
             logargs:=logargs+','+Args[i];
         end;
-      Log(vDebug,SLogRunAction,[AAction,logargs]);
-      Execute(Args);
+      Log(vDebug,SLogRunAction+' start',[AAction,logargs]);
+      result:=Execute(Args);
+      Log(vDebug,SLogRunAction+' end',[AAction,logargs]);
     finally
       Free;
     end;
@@ -150,7 +167,7 @@ begin
   if CurrentPackage=nil then
     Result:='.'
   else
-    Result:=Defaults.BuildDir+CurrentPackage.Name;
+    Result:=GlobalOptions.BuildDir+CurrentPackage.Name;
 end;
 
 function TPackageHandler.PackageRemoteArchive: String;
@@ -160,14 +177,14 @@ begin
   if CurrentPackage.ExternalURL<>'' then
     Result:=CurrentPackage.ExternalURL
   else
-    Result:=Defaults.RemoteRepository+CurrentPackage.FileName;
+    Result:=GlobalOptions.RemoteRepository+CurrentPackage.FileName;
 end;
 
 function TPackageHandler.PackageLocalArchive: String;
 begin
   if not assigned(CurrentPackage) then
     Error(SErrNoPackageSpecified);
-  Result:=Defaults.PackagesDir+CurrentPackage.FileName;
+  Result:=GlobalOptions.PackagesDir+CurrentPackage.FileName;
 end;
 
 
@@ -182,7 +199,8 @@ begin
   if assigned(CurrentPackage) then
     Result:='['+CurrentPackage.Name+'] '
   else
-    Result:='[<currentdir>] ';
+//    Result:='[<currentdir>] ';
+    Result:='';
 end;
 
 
@@ -277,6 +295,8 @@ end;
 
 initialization
   PkgHandlerList:=TFPHashList.Create;
+  ExecutedActions:=TFPHashList.Create;
 finalization
   FreeAndNil(PkgHandlerList);
+  FreeAndNil(ExecutedActions);
 end.

+ 2 - 3
utils/fppkg/pkglnet.pp

@@ -142,7 +142,7 @@ begin
     FHTTP.Host := URI.Host;
     FHTTP.Method := hmGet;
     FHTTP.Port := URI.Port;
-    FHTTP.URI := '/' + URI.Document;
+    FHTTP.URI := URI.Path + URI.Document;
     FHTTP.SendRequest;
 
     FQuit:=False;
@@ -175,6 +175,5 @@ begin
 end;
 
 initialization
-  DownloaderClass:=TLNetDownloader;
-
+  RegisterDownloader('lnet',TLNetDownloader);
 end.

+ 22 - 6
utils/fppkg/pkgmessages.pp

@@ -6,7 +6,9 @@ interface
 
 
 Resourcestring
+  SError                     = 'Error: ';
   SWarning                   = 'Warning: ';
+  SDebug                     = 'Debug: ';
 
   SErrInValidArgument        = 'Invalid command-line argument at position %d : %s';
   SErrNeedArgument           = 'Option at position %d (%s) needs an argument';
@@ -15,9 +17,13 @@ Resourcestring
   SErrMissingFPMake          = 'Missing configuration fpmake.pp';
   SErrMissingMakefilefpc     = 'Missing configuration Makefile.fpc';
   SErrMissingDirectory       = 'Missing directory "%s"';
+  SErrMissingCompilerConfig  = 'Could not find compiler configuration "%s"';
+  SErrMissingInstallPackage  = 'Could not find package "%s"';
   SErrNoPackageSpecified     = 'No package specified';
+  SErrNoPackageAvailable     = 'Package %s %s is not available';
   SErrOnlyLocalDir           = 'The speficied command "%s" works only on current dir, not on a (remote) package';
-  SErrRunning                = 'The FPC make tool encountered the following error:';
+  SErrExecutionFPMake        = 'Execution of FPMake %s failed';
+  SErrException              = 'The FPC Package tool encountered the following error:';
   SErrActionAlreadyRegistered= 'Action "%s" is already registered';
   SErrActionNotFound         = 'Action "%s" is not supported';
   SErrFailedToCompileFPCMake = 'Could not compile fpmake driver program';
@@ -31,14 +37,13 @@ Resourcestring
   SErrInvalidVerbosity       = 'Invalid verbosity string: "%s"';
   SErrInvalidCommand         = 'Invalid command: %s';
   SErrChangeDirFailed        = 'Could not change directory to "%s"';
+  SErrCorruptPackagesFile    = 'Packages file "%s" is corrupt, delete file manual and retry';
 
   SErrHTTPGetFailed          = 'HTTP Download failed.';
   SErrLoginFailed            = 'FTP LOGIN command failed.';
   SErrCWDFailed              = 'FTP CWD "%s" command failed.';
   SErrGETFailed              = 'FTP GET "%s" command failed.';
 
-  SWarnFPMKUnitNotFound      = 'Unit directory of fpmkunit is not found, compiling fpmake may file';
-
   SLogGeneratingFPMake       = 'Generating fpmake.pp';
   SLogNotCompilingFPMake     = 'Skipping compiling of fpmake.pp, fpmake executable already exists';
   SLogCommandLineAction      = 'Adding action from commandline: "%s %s"';
@@ -50,12 +55,23 @@ Resourcestring
   SLogZippping               = 'Zipping "%s"';
   SLogLoadingGlobalConfig    = 'Loading global configuration from "%s"';
   SLogLoadingCompilerConfig  = 'Loading compiler configuration from "%s"';
+  SLogLoadingFPMakeCompilerConfig = 'Loading compiler configuration for fpmake building from "%s"';
   SLogGeneratingGlobalConfig = 'Generating default global configuration in "%s"';
   SLogDetectedCompiler       = 'Detected compiler "%s" (version %s for %s)';
-  SLogDetectedFPCDIR         = 'Detected FPCDIR "%s" will be used installation';
+  SLogDetectedFPCDIR         = 'Detected %s FPCDIR "%s"';
   SLogGeneratingCompilerConfig  = 'Generating default compiler configuration in "%s"';
-  SLogLoadingPackagesFile    = 'Loading packages information from "%s"';
-  SLogLoadingVersionsFile    = 'Loading local versions information from "%s"';
+  SLogLoadingPackagesFile    = 'Loading available packages from "%s"';
+  SLogLoadingStatusFile      = 'Loading local status from "%s"';
+  SLogSavingStatusFile       = 'Saving local status to "%s"';
+  SLogFPMKUnitDepVersion     = 'Checking for %s %s, installed %s, available %s';
+  SLogFPMKUnitDepTooOld      = 'Minimum version of %s is not installed, using internal fpmkunit with limited functionality';
+
+  SDbgFound                  = 'Found';
+  SDbgNotFound               = 'Not Found';
+  SDbgDirectoryExists        = 'Directory "%s" %s';
+  SDbgFileExists             = 'File "%s" %s';
+  SDbgBackupFile             = 'Creating Backup File "%s"';
+  SDbgPackageDependency      = 'Dependency on package %s %s, installed %s, available %s  (%s)';
 
 
 implementation

+ 288 - 173
utils/fppkg/pkgoptions.pp

@@ -20,84 +20,108 @@ uses Classes, Sysutils, Inifiles, fprepos;
 
 Const
   DefaultManifestFile      = 'manifest.xml';
+  CurrentConfigVersion     = '0.1';
 
 Type
 
-  { TPackagerOptions }
+  { TGlobalOptions }
 
-  TPackagerOptions = Class(TPersistent)
+  TGlobalOptions = Class(TPersistent)
   private
-    FDirty: Boolean;
-    // Global options
-    FRemoteMirrorsLocation : String;
-    FLocalMirrorsLocation : String;
-    FRemoteRepository : String;
-    FLocalRepository : String;
+    FDirty : Boolean;
+    FConfigVersion,
+    FRemoteMirrorsLocation,
+    FLocalMirrorsLocation,
+    FRemoteRepository,
+    FLocalRepository,
     FCompilerConfigDir,
     FPackagesDir,
-    FBuildDir : String;
+    FBuildDir,
     FDefaultVerbosity,
-    FCurrentCompilerConfig,
-    FDefaultCompilerConfig : String;
-    // Compiler specific options
-    FCompiler : String;
-    FCompilerCPU: TCPU;
-    FCompilerOS: TOS;
-    FCompilerVersion : String;
-    FInstallDir : String;
-    // Compiler settings for compiling FPMake.pp
-    FFPMakeCompiler : String;
-    FFPMakeUnitDir : String;
-    function GetOptString(Index: integer): String;
+    FDownloader,
+    FDefaultCompilerConfig,
+    FFPMakeCompilerConfig : String;
+    // Parameter options
+    FCompilerConfig : String;
+    FInstallGlobal  : Boolean;
+    function  GetOptString(Index: integer): String;
     procedure SetOptString(Index: integer; const AValue: String);
-    procedure SetCompilerCPU(const AValue: TCPU);
-    procedure SetCompilerOS(const AValue: TOS);
   Public
     Constructor Create;
     Procedure InitGlobalDefaults;
     Procedure LoadGlobalFromIni(Ini : TCustomIniFile); virtual;
     Procedure SaveGlobalToIni(Ini : TCustomIniFile); virtual;
-    Procedure LoadGlobalFromFile(FileName : String);
-    Procedure SaveGlobalToFile(FileName : String);
-    Procedure InitCompilerDefaults;
-    Procedure LoadCompilerFromIni(Ini : TCustomIniFile); virtual;
-    Procedure SaveCompilerToIni(Ini : TCustomIniFile); virtual;
-    Procedure LoadCompilerFromFile(FileName : String);
-    Procedure SaveCompilerToFile(FileName : String);
+    Procedure LoadGlobalFromFile(const AFileName : String);
+    Procedure SaveGlobalToFile(const AFileName : String);
     Property Dirty : Boolean Read FDirty;
+    Property ConfigVersion : String read FConfigVersion;
     function RemotePackagesFile:string;
     function LocalPackagesFile:string;
-    function LocalVersionsFile(CompilerConfig:String):string;
+    function LocalVersionsFile(const ACompilerConfig:String):string;
   Published
     Property RemoteMirrorsLocation : String Index 0 Read GetOptString Write SetOptString;
     Property LocalMirrorsLocation : String Index 1 Read GetOptString Write SetOptString;
     Property RemoteRepository : String Index 2 Read GetOptString Write SetOptString;
     Property LocalRepository : String Index 3 Read GetOptString Write SetOptString;
-    Property BuildDir : String Index 5 Read GetOptString Write SetOptString;
-    Property Compiler : String Index 6 Read GetOptString Write SetOptString;
-    Property CompilerTarget : String Index 7 Read GetOptString Write SetOptString;
+    Property BuildDir : String Index 4 Read GetOptString Write SetOptString;
+    Property PackagesDir : String Index 5 Read GetOptString Write SetOptString;
+    Property CompilerConfigDir : String Index 6 Read GetOptString Write SetOptString;
+    Property DefaultVerbosity : String Index 7 Read GetOptString Write SetOptString;
     Property DefaultCompilerConfig : String Index 8 Read GetOptString Write SetOptString;
-    Property CompilerVersion : String Index 9 Read GetOptString Write SetOptString;
-    Property InstallDir : String Index 10 Read GetOptString Write SetOptString;
-    Property DefaultVerbosity : String Index 11 Read GetOptString Write SetOptString;
-    Property PackagesDir : String Index 12 Read GetOptString Write SetOptString;
-    Property CompilerConfigDir : String Index 13 Read GetOptString Write SetOptString;
-    Property FPMakeCompiler : String Index 14 Read GetOptString Write SetOptString;
-    Property FPMakeUnitDir : String Index 15 Read GetOptString Write SetOptString;
-    Property CurrentCompilerConfig : String Index 16 Read GetOptString Write SetOptString;
+    Property FPMakeCompilerConfig : String Index 9 Read GetOptString Write SetOptString;
+    Property Downloader: String Index 10 Read GetOptString Write SetOptString;
+    // Parameters
+    Property CompilerConfig : String Read FCompilerConfig Write FCompilerConfig;
+    Property InstallGlobal : Boolean Read FInstallGlobal Write FInstallGlobal;
+  end;
+
+
+  { TCompilerOptions }
+
+  TCompilerOptions = Class(TPersistent)
+  private
+    FDirty: Boolean;
+    FConfigVersion,
+    FCompiler,
+    FCompilerVersion,
+    FLocalInstallDir,
+    FGlobalInstallDir : String;
+    FCompilerCPU: TCPU;
+    FCompilerOS: TOS;
+    function GetOptString(Index: integer): String;
+    procedure SetOptString(Index: integer; const AValue: String);
+    procedure SetCompilerCPU(const AValue: TCPU);
+    procedure SetCompilerOS(const AValue: TOS);
+  Public
+    Constructor Create;
+    Procedure InitCompilerDefaults;
+    Procedure LoadCompilerFromIni(Ini : TCustomIniFile); virtual;
+    Procedure SaveCompilerToIni(Ini : TCustomIniFile); virtual;
+    Procedure LoadCompilerFromFile(const AFileName : String);
+    Procedure SaveCompilerToFile(const AFileName : String);
+    Property Dirty : Boolean Read FDirty;
+    Property ConfigVersion : String read FConfigVersion;
+    Function LocalUnitDir:string;
+    Function GlobalUnitDir:string;
+  Published
+    Property Compiler : String Index 1 Read GetOptString Write SetOptString;
+    Property CompilerTarget : String Index 2 Read GetOptString Write SetOptString;
+    Property CompilerVersion : String Index 3 Read GetOptString Write SetOptString;
+    Property GlobalInstallDir : String Index 4 Read GetOptString Write SetOptString;
+    Property LocalInstallDir : String Index 5 Read GetOptString Write SetOptString;
     Property CompilerOS : TOS Read FCompilerOS Write SetCompilerOS;
     Property CompilerCPU : TCPU Read FCompilerCPU Write SetCompilerCPU;
   end;
 
 var
-  Defaults : TPackagerOptions;
+  GlobalOptions : TGlobalOptions;
+  CompilerOptions : TCompilerOptions;
+  FPMakeCompilerOptions : TCompilerOptions;
+
 
 Implementation
 
 uses
-{$ifdef unix}
-  baseunix,
-{$endif}
   pkgglobals,
   pkgmessages;
 
@@ -107,66 +131,70 @@ Const
   DefaultVersionsFile     = 'versions-%s.dat';
   DefaultMirrorsLocation  = 'http://www.freepascal.org/repository/'+DefaultMirrorFile;
 {$warning TODO use real repository}
-{$ifdef unix}
+{$ifdef localrepository}
   DefaultRemoteRepository = 'file://'+{$I %HOME%}+'/repository/';
 {$else}
-  DefaultRemoteRepository = 'c:/repository/';
+  DefaultRemoteRepository = 'http://www.freepascal.org/~peter/repository/';
 {$endif}
 
   // ini file keys
   SDefaults = 'Defaults';
 
+  // All configs
+  KeyConfigVersion         = 'ConfigVersion';
+
   // Global config
   KeyLocalMirrorsLocation  = 'LocalMirrors';
   KeyRemoteMirrorsLocation = 'RemoteMirrors';
   KeyRemoteRepository      = 'RemoteRepository';
   KeyLocalRepository       = 'LocalRepository';
-  KeyCompilerConfigDir     = 'CompilerConfigDir';
   KeyPackagesDir           = 'PackagesDir';
   KeyBuildDir              = 'BuildDir';
-  KeyCompilerConfig        = 'CompilerConfig';
+  KeyCompilerConfigDir     = 'CompilerConfigDir';
   KeyVerbosity             = 'Verbosity';
+  KeyCompilerConfig        = 'CompilerConfig';
+  KeyFPMakeCompilerConfig  = 'FPMakeCompilerConfig';
+  KeyDownloader            = 'Downloader';
+
   // Compiler dependent config
-  KeyInstallDir            = 'InstallDir';
+  KeyGlobalInstallDir      = 'GlobalInstallDir';
+  KeyLocalInstallDir       = 'LocalInstallDir';
   KeyCompiler              = 'Compiler' ;
   KeyCompilerOS            = 'OS';
   KeyCompilerCPU           = 'CPU';
   KeyCompilerVersion       = 'Version';
-  KeyFPMakeCompiler        = 'FPMakeCompiler';
-  KeyFPMakeUnitDir         = 'FPMakeUnitDir';
 
 
-{ TPackagerOptions }
+{*****************************************************************************
+                           TGlobalOptions
+*****************************************************************************}
 
-constructor TPackagerOptions.Create;
+constructor TGlobalOptions.Create;
 begin
   InitGlobalDefaults;
 end;
 
 
-function TPackagerOptions.GetOptString(Index: integer): String;
+function TGlobalOptions.GetOptString(Index: integer): String;
 begin
   Case Index of
     0 : Result:=FRemoteMirrorsLocation;
     1 : Result:=FLocalMirrorsLocation;
     2 : Result:=FRemoteRepository;
     3 : Result:=FLocalRepository;
-    5 : Result:=FBuildDir;
-    6 : Result:=FCompiler;
-    7 : Result:=MakeTargetString(CompilerCPU,CompilerOS);
+    4 : Result:=FBuildDir;
+    5 : Result:=FPackagesDir;
+    6 : Result:=FCompilerConfigDir;
+    7 : Result:=FDefaultVerbosity;
     8 : Result:=FDefaultCompilerConfig;
-    9 : Result:=FCompilerVersion;
-   10 : Result:=FInstallDir;
-   11 : Result:=FDefaultVerbosity;
-   12 : Result:=FPackagesDir;
-   13 : Result:=FCompilerConfigDir;
-   14 : Result:=FFPMakeCompiler;
-   15 : Result:=FFPMakeUnitDir;
-   16 : Result:=FCurrentCompilerConfig;
+    9 : Result:=FFPMakeCompilerConfig;
+   10 : Result:=FDownloader;
+    else
+      Error('Unknown option');
   end;
 end;
 
-procedure TPackagerOptions.SetOptString(Index: integer; const AValue: String);
+procedure TGlobalOptions.SetOptString(Index: integer; const AValue: String);
 begin
   If AValue=GetOptString(Index) then
     Exit;
@@ -175,65 +203,46 @@ begin
     1 : FRemoteMirrorsLocation:=AValue;
     2 : FRemoteRepository:=AValue;
     3 : FLocalRepository:=AValue;
-    5 : FBuildDir:=FixPath(AValue);
-    6 : FCompiler:=AValue;
-    7 : StringToCPUOS(AValue,FCompilerCPU,FCompilerOS);
+    4 : FBuildDir:=FixPath(AValue);
+    5 : FPackagesDir:=FixPath(AValue);
+    6 : FCompilerConfigDir:=FixPath(AValue);
+    7 : FDefaultVerbosity:=AValue;
     8 : FDefaultCompilerConfig:=AValue;
-    9 : FCompilerVersion:=AValue;
-   10 : FInstallDir:=FixPath(AValue);
-   11 : FDefaultVerbosity:=AValue;
-   12 : FPackagesDir:=FixPath(AValue);
-   13 : FCompilerConfigDir:=FixPath(AValue);
-   14 : FFPMakeCompiler:=AValue;
-   15 : FFPMakeUnitDir:=FixPath(AValue);
-   16 : FCurrentCompilerConfig:=AValue;
+    9 : FFPMakeCompilerConfig:=AValue;
+   10 : FDownloader:=AValue;
+    else
+      Error('Unknown option');
   end;
   FDirty:=True;
 end;
 
 
-procedure TPackagerOptions.SetCompilerCPU(const AValue: TCPU);
-begin
-  if FCompilerCPU=AValue then
-    exit;
-  FCompilerCPU:=AValue;
-  FDirty:=True;
-end;
-
-
-procedure TPackagerOptions.SetCompilerOS(const AValue: TOS);
-begin
-  if FCompilerOS=AValue then
-    exit;
-  FCompilerOS:=AValue;
-  FDirty:=True;
-end;
-
-
-function TPackagerOptions.RemotePackagesFile:string;
+function TGlobalOptions.RemotePackagesFile:string;
 begin
   Result:=FRemoteRepository+DefaultPackagesFile;
 end;
 
 
-function TPackagerOptions.LocalPackagesFile:string;
+function TGlobalOptions.LocalPackagesFile:string;
 begin
   Result:=FLocalRepository+DefaultPackagesFile;
 end;
 
 
-function TPackagerOptions.LocalVersionsFile(CompilerConfig:String):string;
+function TGlobalOptions.LocalVersionsFile(const ACompilerConfig:String):string;
 begin
-  Result:=FLocalRepository+Format(DefaultVersionsFile,[CompilerConfig]);
+  Result:=FLocalRepository+Format(DefaultVersionsFile,[ACompilerConfig]);
 end;
 
-Procedure TPackagerOptions.InitGlobalDefaults;
+
+Procedure TGlobalOptions.InitGlobalDefaults;
 var
   LocalDir : String;
 begin
+  FConfigVersion:=CurrentConfigVersion;
   // Retrieve Local fppkg directory
 {$ifdef unix}
-  if (fpGetUID=0) then
+  if IsSuperUser then
     begin
       if DirectoryExists('/usr/local/lib/fpc') then
         LocalDir:='/usr/local/lib/fpc/fppkg/'
@@ -256,62 +265,28 @@ begin
   FRemoteMirrorsLocation:=DefaultMirrorsLocation;
   FRemoteRepository:=DefaultRemoteRepository;
   // Other config
-  FDefaultCompilerConfig:='default';
-  FCurrentCompilerConfig:=FDefaultCompilerConfig;
   FDefaultVerbosity:='error,warning,info,debug,commands';
+  FDefaultCompilerConfig:='default';
+  FFPMakeCompilerConfig:='default';
+  // Downloader
+{$if defined(unix) or defined(windows)}
+  FDownloader:='lnet';
+{$else}
+  FDownloader:='base';
+{$endif}
+  // Parameter defaults
+  FCompilerConfig:=FDefaultCompilerConfig;
+  FInstallGlobal:=False;
 end;
 
 
-Procedure TPackagerOptions.InitCompilerDefaults;
-var
-  infoSL : TStringList;
-begin
-  FCompiler:=FileSearch('fpc'+ExeExt,GetEnvironmentVariable('PATH'));
-  if FCompiler='' then
-    Raise EPackagerError.Create(SErrMissingFPC);
-  // Detect compiler version/target from -i option
-  infosl:=TStringList.Create;
-  infosl.Delimiter:=' ';
-  infosl.DelimitedText:=GetCompilerInfo(FCompiler,'-iVTPTO');
-  if infosl.Count<>3 then
-    Raise EPackagerError.Create(SErrInvalidFPCInfo);
-  FCompilerVersion:=infosl[0];
-  FCompilerCPU:=StringToCPU(infosl[1]);
-  FCompilerOS:=StringToOS(infosl[2]);
-  Log(vDebug,SLogDetectedCompiler,[FCompiler,FCompilerVersion,MakeTargetString(FCompilerCPU,FCompilerOS)]);
-  // Use the same algorithm as the compiler, see options.pas
-{$ifdef Unix}
-  FInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
-  if FInstallDir='' then
-    begin
-      FInstallDir:='/usr/local/lib/fpc/'+FCompilerVersion+'/';
-      if not DirectoryExists(FInstallDir) and
-         DirectoryExists('/usr/lib/fpc/'+FCompilerVersion) then
-        FInstallDir:='/usr/lib/fpc/'+FCompilerVersion+'/';
-    end;
-{$else unix}
-  FInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
-  if FInstallDir='' then
-    begin
-      FInstallDir:=ExtractFilePath(FCompiler)+'../';
-      if not(DirectoryExists(FInstallDir+'/units')) and
-         not(DirectoryExists(FInstallDir+'/rtl')) then
-        FInstallDir:=FInstallDir+'../';
-    end;
-{$endif unix}
-  Log(vDebug,SLogDetectedFPCDIR,[FInstallDir]);
-  // Detect directory where fpmake units are located
-  FFPMakeCompiler:=FCompiler;
-  FFPMakeUnitDir:=FInstallDir+'units'+PathDelim+CompilerTarget+PathDelim+'fpmkunit'+PathDelim;
-  if not DirectoryExists(FFPMakeUnitDir) then
-    Log(vWarning,SWarnFPMKUnitNotFound);
-end;
-
-
-procedure TPackagerOptions.LoadGlobalFromIni(Ini: TCustomIniFile);
+procedure TGlobalOptions.LoadGlobalFromIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
+     FConfigVersion:=ReadString(SDefaults,KeyConfigVersion,'');
+     if FConfigVersion<>CurrentConfigVersion then
+       Error('Old configuration found, please delete manual');
      FLocalMirrorsLocation:=ReadString(SDefaults,KeyLocalMirrorsLocation,FLocalMirrorsLocation);
      FRemoteMirrorsLocation:=ReadString(SDefaults,KeyRemoteMirrorsLocation,FRemoteMirrorsLocation);
      FRemoteRepository:=ReadString(SDefaults,KeyRemoteRepository,FRemoteRepository);
@@ -319,16 +294,19 @@ begin
      FBuildDir:=FixPath(ReadString(SDefaults,KeyBuildDir,FBuildDir));
      FPackagesDir:=FixPath(ReadString(SDefaults,KeyPackagesDir,FPackagesDir));
      FCompilerConfigDir:=FixPath(ReadString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir));
-     FDefaultCompilerConfig:=ReadString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
      FDefaultVerbosity:=ReadString(SDefaults,KeyVerbosity,FDefaultVerbosity);
+     FDefaultCompilerConfig:=ReadString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
+     FFPMakeCompilerConfig:=ReadString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
+     FDownloader:=ReadString(SDefaults,KeyDownloader,FDownloader);
    end;
 end;
 
 
-procedure TPackagerOptions.SaveGlobalToIni(Ini: TCustomIniFile);
+procedure TGlobalOptions.SaveGlobalToIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
+     WriteString(SDefaults,KeyConfigVersion,FConfigVersion);
      WriteString(SDefaults,KeyBuildDir,FBuildDir);
      WriteString(SDefaults,KeyPackagesDir,FPackagesDir);
      WriteString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir);
@@ -336,17 +314,19 @@ begin
      WriteString(SDefaults,KeyLocalMirrorsLocation,FLocalMirrorsLocation);
      WriteString(SDefaults,KeyRemoteMirrorsLocation,FRemoteMirrorsLocation);
      WriteString(SDefaults,KeyRemoteRepository,FRemoteRepository);
-     WriteString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
      WriteString(SDefaults,KeyVerbosity,FDefaultVerbosity);
+     WriteString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
+     WriteString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
+     WriteString(SDefaults,KeyDownloader,FDownloader);
    end;
 end;
 
 
-procedure TPackagerOptions.LoadGlobalFromFile(FileName: String);
+procedure TGlobalOptions.LoadGlobalFromFile(const AFileName: String);
 Var
   Ini : TMemIniFile;
 begin
-  Ini:=TMemIniFile.Create(FileName);
+  Ini:=TMemIniFile.Create(AFileName);
   try
     LoadGlobalFromIni(Ini);
   finally
@@ -355,11 +335,13 @@ begin
 end;
 
 
-procedure TPackagerOptions.SaveGlobalToFile(FileName: String);
+procedure TGlobalOptions.SaveGlobalToFile(const AFileName: String);
 Var
   Ini : TIniFile;
 begin
-  Ini:=TIniFile.Create(FileName);
+  if FileExists(AFileName) then
+    BackupFile(AFileName);
+  Ini:=TIniFile.Create(AFileName);
   try
     SaveGlobalToIni(Ini);
     Ini.UpdateFile;
@@ -369,41 +351,167 @@ begin
 end;
 
 
-procedure TPackagerOptions.LoadCompilerFromIni(Ini: TCustomIniFile);
+{*****************************************************************************
+                           TCompilerOptions
+*****************************************************************************}
+
+constructor TCompilerOptions.Create;
+begin
+end;
+
+
+function TCompilerOptions.GetOptString(Index: integer): String;
+begin
+  Case Index of
+    1 : Result:=FCompiler;
+    2 : Result:=MakeTargetString(CompilerCPU,CompilerOS);
+    3 : Result:=FCompilerVersion;
+    4 : Result:=FGlobalInstallDir;
+    5 : Result:=FLocalInstallDir;
+    else
+      Error('Unknown option');
+  end;
+end;
+
+procedure TCompilerOptions.SetOptString(Index: integer; const AValue: String);
+begin
+  If AValue=GetOptString(Index) then
+    Exit;
+  Case Index of
+    1 : FCompiler:=AValue;
+    2 : StringToCPUOS(AValue,FCompilerCPU,FCompilerOS);
+    3 : FCompilerVersion:=AValue;
+    4 : FGlobalInstallDir:=FixPath(AValue);
+    5 : FLocalInstallDir:=FixPath(AValue);
+    else
+      Error('Unknown option');
+  end;
+  FDirty:=True;
+end;
+
+
+procedure TCompilerOptions.SetCompilerCPU(const AValue: TCPU);
+begin
+  if FCompilerCPU=AValue then
+    exit;
+  FCompilerCPU:=AValue;
+  FDirty:=True;
+end;
+
+
+procedure TCompilerOptions.SetCompilerOS(const AValue: TOS);
+begin
+  if FCompilerOS=AValue then
+    exit;
+  FCompilerOS:=AValue;
+  FDirty:=True;
+end;
+
+
+function TCompilerOptions.LocalUnitDir:string;
+begin
+  if FLocalInstallDir<>'' then
+    result:=FLocalInstallDir+'units'+PathDelim+CompilerTarget+PathDelim
+  else
+    result:='';
+end;
+
+
+function TCompilerOptions.GlobalUnitDir:string;
+begin
+  if FGlobalInstallDir<>'' then
+    result:=FGlobalInstallDir+'units'+PathDelim+CompilerTarget+PathDelim
+  else
+    result:='';
+end;
+
+
+procedure TCompilerOptions.InitCompilerDefaults;
+var
+  infoSL : TStringList;
+begin
+  FConfigVersion:=CurrentConfigVersion;
+  FCompiler:=FileSearch('fpc'+ExeExt,GetEnvironmentVariable('PATH'));
+  if FCompiler='' then
+    Raise EPackagerError.Create(SErrMissingFPC);
+  // Detect compiler version/target from -i option
+  infosl:=TStringList.Create;
+  infosl.Delimiter:=' ';
+  infosl.DelimitedText:=GetCompilerInfo(FCompiler,'-iVTPTO');
+  if infosl.Count<>3 then
+    Raise EPackagerError.Create(SErrInvalidFPCInfo);
+  FCompilerVersion:=infosl[0];
+  FCompilerCPU:=StringToCPU(infosl[1]);
+  FCompilerOS:=StringToOS(infosl[2]);
+  Log(vDebug,SLogDetectedCompiler,[FCompiler,FCompilerVersion,MakeTargetString(FCompilerCPU,FCompilerOS)]);
+  // Use the same algorithm as the compiler, see options.pas
+{$ifdef Unix}
+  FGlobalInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
+  if FGlobalInstallDir='' then
+    begin
+      FGlobalInstallDir:='/usr/local/lib/fpc/'+FCompilerVersion+'/';
+      if not DirectoryExists(FGlobalInstallDir) and
+         DirectoryExists('/usr/lib/fpc/'+FCompilerVersion) then
+        FGlobalInstallDir:='/usr/lib/fpc/'+FCompilerVersion+'/';
+    end;
+{$else unix}
+  FGlobalInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
+  if FGlobalInstallDir='' then
+    begin
+      FGlobalInstallDir:=ExtractFilePath(FCompiler)+'../';
+      if not(DirectoryExists(FGlobalInstallDir+'/units')) and
+         not(DirectoryExists(FGlobalInstallDir+'/rtl')) then
+        FGlobalInstallDir:=FGlobalInstallDir+'../';
+    end;
+  FGlobalInstallDir:=ExpandFileName(FGlobalInstallDir);
+{$endif unix}
+  Log(vDebug,SLogDetectedFPCDIR,['global',FGlobalInstallDir]);
+  // User writable install directory
+  if not IsSuperUser then
+    begin
+      FLocalInstallDir:=GlobalOptions.LocalRepository+'lib'+PathDelim+FCompilerVersion+PathDelim;
+      Log(vDebug,SLogDetectedFPCDIR,['local',FLocalInstallDir]);
+    end;
+ end;
+
+
+procedure TCompilerOptions.LoadCompilerFromIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
-     FInstallDir:=FixPath(ReadString(SDefaults,KeyInstallDir,FInstallDir));
+     FConfigVersion:=ReadString(SDefaults,KeyConfigVersion,'');
+     if FConfigVersion<>CurrentConfigVersion then
+       Error('Old configuration found, please delete manual');
+     FGlobalInstallDir:=FixPath(ReadString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir));
+     FLocalInstallDir:=FixPath(ReadString(SDefaults,KeyLocalInstallDir,FLocalInstallDir));
      FCompiler:=ReadString(SDefaults,KeyCompiler,FCompiler);
      FCompilerOS:=StringToOS(ReadString(SDefaults,KeyCompilerOS,OSToString(CompilerOS)));
      FCompilerCPU:=StringToCPU(ReadString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU)));
      FCompilerVersion:=ReadString(SDefaults,KeyCompilerVersion,FCompilerVersion);
-     FFPMakeCompiler:=ReadString(SDefaults,KeyFPMakeCompiler,FFPMakeCompiler);
-     FFPMakeUnitDir:=FixPath(ReadString(SDefaults,KeyFPMakeUnitDir,FFPMakeUnitDir));
    end;
 end;
 
 
-procedure TPackagerOptions.SaveCompilerToIni(Ini: TCustomIniFile);
+procedure TCompilerOptions.SaveCompilerToIni(Ini: TCustomIniFile);
 begin
  With Ini do
    begin
-     WriteString(SDefaults,KeyInstallDir,FInstallDir);
+     WriteString(SDefaults,KeyConfigVersion,FConfigVersion);
+     WriteString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir);
+     WriteString(SDefaults,KeyLocalInstallDir,FLocalInstallDir);
      WriteString(SDefaults,KeyCompiler,FCompiler);
      WriteString(SDefaults,KeyCompilerOS,OSToString(CompilerOS));
      WriteString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU));
      WriteString(SDefaults,KeyCompilerVersion,FCompilerVersion);
-     WriteString(SDefaults,KeyFPMakeCompiler,FFPMakeCompiler);
-     WriteString(SDefaults,KeyFPMakeUnitDir,FFPMakeUnitDir);
    end;
 end;
 
 
-procedure TPackagerOptions.LoadCompilerFromFile(FileName: String);
+procedure TCompilerOptions.LoadCompilerFromFile(const AFileName: String);
 Var
   Ini : TMemIniFile;
 begin
-  Ini:=TMemIniFile.Create(FileName);
+  Ini:=TMemIniFile.Create(AFileName);
   try
     LoadCompilerFromIni(Ini);
   finally
@@ -412,11 +520,13 @@ begin
 end;
 
 
-procedure TPackagerOptions.SaveCompilerToFile(FileName: String);
+procedure TCompilerOptions.SaveCompilerToFile(const AFileName: String);
 Var
   Ini : TIniFile;
 begin
-  Ini:=TIniFile.Create(FileName);
+  if FileExists(AFileName) then
+    BackupFile(AFileName);
+  Ini:=TIniFile.Create(AFileName);
   try
     SaveCompilerToIni(Ini);
     Ini.UpdateFile;
@@ -425,8 +535,13 @@ begin
   end;
 end;
 
+
 initialization
-  Defaults:=TPackagerOptions.Create;
+  GlobalOptions:=TGlobalOptions.Create;
+  CompilerOptions:=TCompilerOptions.Create;
+  FPMakeCompilerOptions:=TCompilerOptions.Create;
 finalization
-  FreeAndNil(Defaults);
+  FreeAndNil(GlobalOptions);
+  FreeAndNil(CompilerOptions);
+  FreeAndNil(FPMakeCompilerOptions);
 end.

+ 120 - 30
utils/fppkg/pkgrepos.pp

@@ -9,9 +9,14 @@ uses
   fprepos;
 
 procedure LoadLocalRepository;
-procedure SaveRepository;
-procedure ListRepository;
-procedure RebuildRepository;
+procedure LoadLocalStatus;
+procedure SaveLocalStatus;
+procedure LoadFPMakeLocalStatus;
+procedure ListLocalRepository(all:boolean=false);
+
+procedure ListRemoteRepository;
+procedure RebuildRemoteRepository;
+procedure SaveRemoteRepository;
 
 var
   CurrentRepository : TFPRepository;
@@ -26,6 +31,9 @@ uses
   pkgoptions,
   pkgmessages;
 
+{*****************************************************************************
+                           Local Repository
+*****************************************************************************}
 
 procedure LoadLocalRepository;
 var
@@ -36,55 +44,119 @@ begin
     CurrentRepository.Free;
   CurrentRepository:=TFPRepository.Create(Nil);
   // Repository
-  Log(vDebug,SLogLoadingPackagesFile,[Defaults.LocalPackagesFile]);
-  if FileExists(Defaults.LocalPackagesFile) then
-    begin
-      X:=TFPXMLRepositoryHandler.Create;
-      With X do
-        try
-          LoadFromXml(CurrentRepository,Defaults.LocalPackagesFile);
-        finally
-          Free;
-        end;
-    end;
-  // Versions
-  S:=Defaults.LocalVersionsFile(Defaults.CurrentCompilerConfig);
-  Log(vDebug,SLogLoadingVersionsFile,[S]);
+  S:=GlobalOptions.LocalPackagesFile;
+  Log(vDebug,SLogLoadingPackagesFile,[S]);
+  if not FileExists(S) then
+    exit;
+  try
+    X:=TFPXMLRepositoryHandler.Create;
+    With X do
+      try
+        LoadFromXml(CurrentRepository,S);
+      finally
+        Free;
+      end;
+  except
+    on E : Exception do
+      begin
+        Log(vError,E.Message);
+        Error(SErrCorruptPackagesFile,[S]);
+      end;
+  end;
+end;
+
+
+procedure LoadLocalStatus;
+var
+  S : String;
+begin
+  S:=GlobalOptions.LocalVersionsFile(GlobalOptions.CompilerConfig);
+  Log(vDebug,SLogLoadingStatusFile,[S]);
+  CurrentRepository.ClearStatus;
   if FileExists(S) then
     CurrentRepository.LoadStatusFromFile(S);
 end;
 
 
-procedure SaveRepository;
+procedure SaveLocalStatus;
 var
-  X : TFPXMLRepositoryHandler;
+  S : String;
 begin
-  // Repository
-  Writeln('Saving repository in packages.xml');
-  X:=TFPXMLRepositoryHandler.Create;
-  With X do
-    try
-      SaveToXml(CurrentRepository,'packages.xml');
-    finally
-      Free;
+  S:=GlobalOptions.LocalVersionsFile(GlobalOptions.CompilerConfig);
+  Log(vDebug,SLogSavingStatusFile,[S]);
+  CurrentRepository.SaveStatusToFile(S);
+end;
+
+
+procedure LoadFPMakeLocalStatus;
+var
+  i : Integer;
+  S : String;
+  P : TFPPackage;
+  ReqVer : TFPVersion;
+begin
+  S:=GlobalOptions.LocalVersionsFile(GlobalOptions.FPMakeCompilerConfig);
+  Log(vDebug,SLogLoadingStatusFile,[S]);
+  CurrentRepository.ClearStatus;
+  if FileExists(S) then
+    CurrentRepository.LoadStatusFromFile(S);
+  // Check for fpmkunit dependencies
+  for i:=1 to FPMKUnitDepCount do
+    begin
+      FPMKUnitDepAvailable[i]:=false;
+      P:=CurrentRepository.PackageByName(FPMKUnitDeps[i].package);
+      if P<>nil then
+        begin
+          ReqVer:=TFPVersion.Create;
+          ReqVer.AsString:=FPMKUnitDeps[i].ReqVer;
+          Log(vDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.InstalledVersion.AsString,P.Version.AsString]);
+          if ReqVer.CompareVersion(P.InstalledVersion)<=0 then
+            FPMKUnitDepAvailable[i]:=true
+          else
+            Log(vDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
+        end
+      else
+        Log(vDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
+    end;
+end;
+
+
+procedure ListLocalRepository(all:boolean=false);
+var
+  P : TFPPackage;
+  i : integer;
+begin
+  Writeln(Format('%-20s %-12s %-12s',['Name','Installed','Available']));
+  for i:=0 to CurrentRepository.PackageCount-1 do
+    begin
+      P:=CurrentRepository.Packages[i];
+      if all or (P.Version.CompareVersion(P.InstalledVersion)>0) then
+        begin
+          Writeln(Format('%-20s %-12s %-12s',[P.Name,P.InstalledVersion.AsString,P.Version.AsString]));
+        end;
     end;
 end;
 
 
-procedure ListRepository;
+{*****************************************************************************
+                           Remote Repository
+*****************************************************************************}
+
+procedure ListRemoteRepository;
 var
   P : TFPPackage;
   i : integer;
 begin
+  Writeln(Format('%-20s %-12s %-20s',['Name','Available','FileName']));
   for i:=0 to CurrentRepository.PackageCount-1 do
     begin
       P:=CurrentRepository.Packages[i];
-      Writeln(Format('%-20s %-20s',[P.Name,P.FileName]));
+      Writeln(Format('%-20s %-12s %-20s',[P.Name,P.Version.AsString,P.FileName]));
     end;
 end;
 
 
-procedure RebuildRepository;
+procedure RebuildRemoteRepository;
 var
   X : TFPXMLRepositoryHandler;
   i : integer;
@@ -136,5 +208,23 @@ begin
   end;
 end;
 
+
+procedure SaveRemoteRepository;
+var
+  X : TFPXMLRepositoryHandler;
+begin
+  // Repository
+  Writeln('Saving repository in packages.xml');
+  X:=TFPXMLRepositoryHandler.Create;
+  With X do
+    try
+      SaveToXml(CurrentRepository,'packages.xml');
+    finally
+      Free;
+    end;
+end;
+
+
+
 initialization
 end.

+ 1 - 1
utils/fppkg/pkgwget.pp

@@ -72,5 +72,5 @@ begin
 end;
 
 initialization
-  DownloaderClass:=TWGetDownloader;
+  RegisterDownloader('wget',TWGetDownloader);
 end.