فهرست منبع

Merged revisions 11115-11116,11127,11145,11155,11160-11162,11174-11175,11638-11639,11647-11649,11652,11668,11676,11678,11801,11808,11911 via svnmerge from
svn+ssh://[email protected]/FPC/svn/fpc/trunk

........
r11115 | michael | 2008-05-29 00:31:07 +0200 (Thu, 29 May 2008) | 1 line

* Support for link attribute to description element
........
r11116 | vincents | 2008-05-29 08:02:14 +0200 (Thu, 29 May 2008) | 1 line

fixed compilation on windows
........
r11127 | michael | 2008-05-29 20:31:36 +0200 (Thu, 29 May 2008) | 4 lines

+ Option to sort nodes (in module)
+ Option to omit overridden methods
+ Option to emit declaration for certain declarations.
........
r11145 | michael | 2008-05-31 23:18:12 +0200 (Sat, 31 May 2008) | 1 line

* Added index page generation to html engine
........
r11155 | michael | 2008-06-01 13:48:47 +0200 (Sun, 01 Jun 2008) | 1 line

* Initial support for images
........
r11160 | michael | 2008-06-01 17:38:29 +0200 (Sun, 01 Jun 2008) | 1 line

* Fixed image support
........
r11161 | michael | 2008-06-01 17:42:49 +0200 (Sun, 01 Jun 2008) | 1 line

* Made image support optional
........
r11162 | michael | 2008-06-01 19:38:41 +0200 (Sun, 01 Jun 2008) | 1 line

* Added enumerated values to index page, as they are known identifiers
........
r11174 | michael | 2008-06-02 20:38:09 +0200 (Mon, 02 Jun 2008) | 1 line

* Identifiers can start with _
........
r11175 | michael | 2008-06-02 20:53:21 +0200 (Mon, 02 Jun 2008) | 1 line

* Patch from Graeme Geldenhuys (enhanced) to use span and class when inserting images
........
r11638 | michael | 2008-08-23 13:35:34 +0200 (Sat, 23 Aug 2008) | 1 line

* Patch from Sergei Gorelkin to handle unicode
........
r11639 | michael | 2008-08-23 13:57:16 +0200 (Sat, 23 Aug 2008) | 1 line

* Fixed wrong string type, causing unicode characters to be dropped
........
r11647 | michael | 2008-08-25 11:50:29 +0200 (Mon, 25 Aug 2008) | 1 line

* Created lazarus project file for easier editing
........
r11648 | michael | 2008-08-25 11:52:14 +0200 (Mon, 25 Aug 2008) | 1 line

* Created lazarus project file for easier editing
........
r11649 | michael | 2008-08-25 15:47:06 +0200 (Mon, 25 Aug 2008) | 1 line

* Initial implementation
........
r11652 | michael | 2008-08-25 17:42:14 +0200 (Mon, 25 Aug 2008) | 1 line

* Removed session info
........
r11668 | michael | 2008-08-30 23:05:52 +0200 (Sat, 30 Aug 2008) | 1 line

* Print short description of linked node in class overview
........
r11676 | michael | 2008-08-31 23:09:21 +0200 (Sun, 31 Aug 2008) | 1 line

* Fixed link detection to units that have not yet been scanned
........
r11678 | michael | 2008-08-31 23:25:53 +0200 (Sun, 31 Aug 2008) | 1 line

* Added support for interface delegation (Implements)
........
r11801 | vincents | 2008-09-18 13:49:19 +0200 (Thu, 18 Sep 2008) | 1 line

* fpdoc: fixed memleak
........
r11808 | vincents | 2008-09-19 15:24:22 +0200 (Fri, 19 Sep 2008) | 1 line

* fpdoc: fixed AV when looking for link tags, patch from Michael van Canneyt
........
r11911 | marco | 2008-10-18 14:24:16 +0200 (Sat, 18 Oct 2008) | 2 lines

* Add the main unit URL to the index, the fp IDE uses the index for context sensitive help.
........

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

marco 17 سال پیش
والد
کامیت
9880aa5db5

+ 4 - 0
.gitattributes

@@ -9071,6 +9071,8 @@ utils/fpdoc/dw_txt.pp svneol=native#text/plain
 utils/fpdoc/dw_xml.pp svneol=native#text/plain
 utils/fpdoc/dwlinear.pp svneol=native#text/plain
 utils/fpdoc/dwriter.pp svneol=native#text/plain
+utils/fpdoc/fpclasschart.lpi svneol=native#text/plain
+utils/fpdoc/fpclasschart.pp svneol=native#text/plain
 utils/fpdoc/fpde/Makefile svneol=native#text/plain
 utils/fpdoc/fpde/Makefile.fpc svneol=native#text/plain
 utils/fpdoc/fpde/bitmaps/bold.xpm -text
@@ -9102,6 +9104,7 @@ utils/fpdoc/fpde/frmtable.pp svneol=native#text/plain
 utils/fpdoc/fpde/pgeditor.pp svneol=native#text/plain
 utils/fpdoc/fpde/xpms.pp svneol=native#text/plain
 utils/fpdoc/fpdoc.css -text
+utils/fpdoc/fpdoc.lpi svneol=native#text/plain
 utils/fpdoc/fpdoc.pp svneol=native#text/plain
 utils/fpdoc/intl/Makefile svneol=native#text/plain
 utils/fpdoc/intl/dglobals.de.po svneol=native#text/plain
@@ -9111,6 +9114,7 @@ utils/fpdoc/intl/fpdoc.de.po svneol=native#text/plain
 utils/fpdoc/intl/fpdocmk.de.po svneol=native#text/plain
 utils/fpdoc/intl/fpdocstr.de.po svneol=native#text/plain
 utils/fpdoc/intl/makeskel.de.po svneol=native#text/plain
+utils/fpdoc/makeskel.lpi svneol=native#text/plain
 utils/fpdoc/makeskel.pp svneol=native#text/plain
 utils/fpdoc/sh_pas.pp svneol=native#text/plain
 utils/fpdoc/unitdiff.pp svneol=native#text/plain

+ 43 - 6
utils/fpdoc/dglobals.pp

@@ -46,7 +46,9 @@ resourcestring
   SDocClasses                = 'Classes';
   SDocProceduresAndFunctions = 'Procedures and functions';
   SDocVariables              = 'Variables';
-
+  SDocIdentifierIndex        = 'Index';
+  SDocModuleIndex            = 'Index of all identifiers in unit ''%s''';
+  SDocPackageIndex           = 'Index of all identifiers in package ''%s''';
   SDocUnitOverview           = 'Overview of unit ''%s''';
   SDocOverview               = 'Overview';
   SDocSearch                 = 'Search';
@@ -101,7 +103,11 @@ resourcestring
   // HTML usage
   SHTMLUsageFooter = 'Append xhtml from file as footer to html page';
   SHTMLUsageFooterDate = 'Append footer with date. fmt is Optional format for FormatDateTime';
-  
+  SHTMLUsageCharset = 'Set the HTML character set';
+  SHTMLHtmlSearch = 'Add search page with given name to the menu bar';
+  SHTMLIndexColcount = 'Use N columns in the identifier index pages';
+  SHTMLImageUrl = 'Prefix image URLs with url';
+    
   // CHM usage
   SCHMUsageTOC     = 'Use [File] as the table of contents. Usually a .hhc file.';
   SCHMUsageIndex   = 'Use [File] as the index. Usually a .hhk file.';
@@ -242,7 +248,10 @@ type
 
   // The main FPDoc engine
 
+  { TFPDocEngine }
+
   TFPDocEngine = class(TPasTreeContainer)
+  private
   protected
     DescrDocs: TObjectList;             // List of XML documents
     DescrDocNames: TStringList;         // Names of the XML documents
@@ -269,6 +278,7 @@ type
     procedure AddLink(const APathName, ALinkTo: String);
     function FindAbsoluteLink(const AName: String): String;
     function ResolveLink(AModule: TPasModule; const ALinkDest: String): String;
+    function FindLinkedNode(ANode: TDocNode): TDocNode;
 
     // Documentation file support
     procedure AddDocFile(const AFilename: String);
@@ -1189,24 +1199,51 @@ begin
 end;
 
 function TFPDocEngine.FindShortDescr(AElement: TPasElement): TDOMElement;
+
 var
-  DocNode: TDocNode;
+  DocNode,N: TDocNode;
+
 begin
   DocNode := FindDocNode(AElement);
   if Assigned(DocNode) then
-    Result := DocNode.ShortDescr
+    begin
+    N:=FindLinkedNode(DocNode);
+    If (N<>Nil) then
+      DocNode:=N;
+    Result := DocNode.ShortDescr;
+    end
   else
     Result := nil;
 end;
 
+
+function TFPDocEngine.FindLinkedNode(ANode : TDocNode) : TDocNode;
+
+Var
+  S: String;
+
+begin
+  If (ANode.Link='') then
+    Result:=Nil
+  else
+    Result:=FindDocNode(CurModule,ANode.Link);
+end;
+
 function TFPDocEngine.FindShortDescr(ARefModule: TPasModule;
   const AName: String): TDOMElement;
+
 var
-  DocNode: TDocNode;
+  N,DocNode: TDocNode;
+
 begin
   DocNode := FindDocNode(ARefModule, AName);
   if Assigned(DocNode) then
-    Result := DocNode.ShortDescr
+    begin
+    N:=FindLinkedNode(DocNode);
+    If (N<>Nil) then
+      DocNode:=N;
+    Result := DocNode.ShortDescr;
+    end
   else
     Result := nil;
 end;

+ 398 - 60
utils/fpdoc/dw_html.pp

@@ -19,7 +19,7 @@ unit dw_HTML;
 
 interface
 
-uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter, ChmBase;
+uses Classes, contnrs, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter, ChmBase;
 
 const
   // Subpage indices for modules
@@ -31,6 +31,7 @@ const
   VarsSubindex = 6;
   // Maybe needed later for topic overview ??
   TopicsSubIndex = 7;
+  IndexSubIndex = 8;
 
   // Subpage indices for classes
   PropertiesByInheritanceSubindex = 1;
@@ -107,7 +108,11 @@ type
     FooterFile: string;
     FIDF : Boolean;
     FDateFormat: String;
+    FIndexColCount : Integer;
+    FSearchPage : String;
+    FBaseImageURL : String;
     function ResolveLinkID(const Name: String): DOMString;
+    function ResolveLinkIDInUnit(const Name,UnitName: String): DOMString;
     function ResolveLinkWithinPackage(AElement: TPasElement;
       ASubpageIndex: Integer): String;
 
@@ -117,7 +122,7 @@ type
     function CreateH1(Parent: TDOMNode): THTMLElement;
     function CreateH2(Parent: TDOMNode): THTMLElement;
     function CreateH3(Parent: TDOMNode): THTMLElement;
-    function CreateTable(Parent: TDOMNode): THTMLElement;
+    function CreateTable(Parent: TDOMNode; const AClass: DOMString = ''): THTMLElement;
     function CreateContentTable(Parent: TDOMNode): THTMLElement;
     function CreateTR(Parent: TDOMNode): THTMLElement;
     function CreateTD(Parent: TDOMNode): THTMLElement;
@@ -137,6 +142,7 @@ type
     procedure DescrEndItalic; override;
     procedure DescrBeginEmph; override;
     procedure DescrEndEmph; override;
+    procedure DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString); override;
     procedure DescrWriteFileEl(const AText: DOMString); override;
     procedure DescrWriteKeywordEl(const AText: DOMString); override;
     procedure DescrWriteVarEl(const AText: DOMString); override;
@@ -185,11 +191,11 @@ type
       AShFlags: Byte): Byte;
     Procedure AppendShortDescr(AContext : TPasElement;Parent: TDOMNode; DocNode : TDocNode);
     procedure AppendShortDescr(Parent: TDOMNode; Element: TPasElement);
+    procedure AppendShortDescrCell(Parent: TDOMNode; Element: TPasElement);
     procedure AppendDescr(AContext: TPasElement; Parent: TDOMNode;
       DescrNode: TDOMElement; AutoInsertBlock: Boolean);
     procedure AppendDescrSection(AContext: TPasElement; Parent: TDOMNode;
       DescrNode: TDOMElement; const ATitle: DOMString);
-    procedure AppendShortDescrCell(Parent: TDOMNode; Element: TPasElement);
     function AppendHyperlink(Parent: TDOMNode; Element: TPasElement): TDOMElement;
     function AppendType(CodeEl, TableEl: TDOMElement;
       Element: TPasType; Expanded: Boolean;
@@ -212,9 +218,12 @@ type
     Procedure AppendSeeAlsoSection(AElement : TPasElement;DocNode : TDocNode);
     Procedure AppendExampleSection(AElement : TPasElement;DocNode : TDocNode);
     procedure AppendFooter;
-
+    procedure CreateIndexPage(L : TStringList);
+    procedure CreateModuleIndexPage(AModule: TPasModule);
     procedure CreatePageBody(AElement: TPasElement; ASubpageIndex: Integer); virtual;
     procedure CreatePackagePageBody;
+    procedure CreatePackageIndex;
+    procedure AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
     Procedure CreateTopicPageBody(AElement : TTopicElement);
     procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer);
     procedure CreateConstPageBody(AConst: TPasConst);
@@ -238,7 +247,10 @@ type
     procedure WriteHTMLPages; virtual;
     procedure WriteXHTMLPages;
 
-    SearchPage: String;
+    Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
+    Procedure WriteDoc; override;
+    class procedure Usage(List: TStrings); override;
+    Property SearchPage: String Read FSearchPage Write FSearchPage;
     property Allocator: TFileAllocator read FAllocator;
     property Package: TPasPackage read FPackage;
     property PageCount: Integer read GetPageCount;
@@ -246,9 +258,8 @@ type
     Property DateFormat : String Read FDateFormat Write FDateFormat;
     property OnTest: TNotifyEvent read FOnTest write SetOnTest;
     Property CharSet : String Read FCharSet Write FCharSet;
-    Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
-    Procedure WriteDoc; override;
-    class procedure Usage(List: TStrings); override;
+    Property IndexColCount : Integer Read FIndexColCount write FIndexColCount;
+    Property BaseImageURL : String Read FBaseImageURL Write FBaseImageURL;
   end;
 
   THTMWriter = class(THTMLWriter)
@@ -407,7 +418,25 @@ begin
     Result := '../';
 end;
 
+Type
+
+  { TLinkData }
+
+  TLinkData = Class(TObject)
+    Constructor Create(Const APathName,ALink,AModuleName : string);
+    FPathName,
+    FLink,
+    FModuleName : String;
+  end;
+
+{ TLinkData }
 
+constructor TLinkData.Create(Const APathName, ALink, AModuleName: string);
+begin
+  FPathName:=APathName;
+  FLink:=ALink;
+  FModuleName:=AModuleName;
+end;
 
 constructor THTMLWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
 
@@ -481,34 +510,36 @@ constructor THTMLWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
     end;
   end;
 
-  procedure ScanModule(AModule: TPasModule);
+  procedure ScanModule(AModule: TPasModule; LinkList : TObjectList);
   var
     i, j, k: Integer;
     s: String;
     ClassEl: TPasClassType;
     FPEl, AncestorMemberEl: TPasElement;
     DocNode: TDocNode;
+    ALink : DOMString;
     DidAutolink: Boolean;
   begin
     AddPage(AModule, 0);
+    AddPage(AModule,IndexSubIndex);
     AddTopicPages(AModule);
     with AModule do
-    begin
-      if InterfaceSection.ResStrings.Count > 0 then
       begin
+      if InterfaceSection.ResStrings.Count > 0 then
+        begin
         AddPage(AModule, ResstrSubindex);
         s := Allocator.GetFilename(AModule, ResstrSubindex);
         for i := 0 to InterfaceSection.ResStrings.Count - 1 do
           with TPasResString(InterfaceSection.ResStrings[i]) do
             Engine.AddLink(PathName, s + '#' + LowerCase(Name));
-      end;
+        end;
       AddPages(AModule, ConstsSubindex, InterfaceSection.Consts);
       AddPages(AModule, TypesSubindex, InterfaceSection.Types);
       if InterfaceSection.Classes.Count > 0 then
-      begin
+        begin
         AddPage(AModule, ClassesSubindex);
         for i := 0 to InterfaceSection.Classes.Count - 1 do
-        begin
+          begin
           ClassEl := TPasClassType(InterfaceSection.Classes[i]);
           AddPage(ClassEl, 0);
           // !!!: Only add when there are items
@@ -520,52 +551,65 @@ constructor THTMLWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
           AddPage(ClassEl, EventsByNameSubindex);
 
           for j := 0 to ClassEl.Members.Count - 1 do
-          begin
+            begin
             FPEl := TPasElement(ClassEl.Members[j]);
             if ((FPEl.Visibility = visPrivate) and Engine.HidePrivate) or
               ((FPEl.Visibility = visProtected) and Engine.HideProtected) then
               continue;
 
             DocNode := Engine.FindDocNode(FPEl);
-            if not Assigned(DocNode) then
-            begin
+            if Assigned(DocNode) then
+              begin
+              if Assigned(DocNode.Node) then
+                ALink:=DocNode.Node['link']
+              else
+                ALink:='';
+              If (ALink<>'') then
+                LinkList.Add(TLinkData.Create(FPEl.PathName,ALink,AModule.name))
+              else
+                AddPage(FPEl, 0);
+              end
+            else
+              begin
               DidAutolink := False;
               if Assigned(ClassEl.AncestorType) and
                 (ClassEl.AncestorType.ClassType = TPasClassType) then
-              begin
-                for k := 0 to TPasClassType(ClassEl.AncestorType).Members.Count - 1 do
                 begin
+                for k := 0 to TPasClassType(ClassEl.AncestorType).Members.Count - 1 do
+                  begin
                   AncestorMemberEl :=
                     TPasElement(TPasClassType(ClassEl.AncestorType).Members[k]);
                   if AncestorMemberEl.Name = FPEl.Name then
-                  begin
+                    begin
                     DocNode := Engine.FindDocNode(AncestorMemberEl);
                     if Assigned(DocNode) then
-                    begin
+                      begin
                       DidAutolink := True;
                       Engine.AddLink(FPEl.PathName,
                         Engine.FindAbsoluteLink(AncestorMemberEl.PathName));
                       break;
+                      end;
                     end;
                   end;
                 end;
-              end;
               if not DidAutolink then
                 AddPage(FPEl, 0);
-            end else
-              AddPage(FPEl, 0);
+              end;
+            end;
           end;
         end;
-      end;
       AddPages(AModule, ProcsSubindex, InterfaceSection.Functions);
       AddPages(AModule, VarsSubindex, InterfaceSection.Variables);
-    end;
+      end;
   end;
 
 var
   i: Integer;
+  L : TObjectList;
+
 begin
   inherited ;
+  IndexColCount:=3;
   Charset:='iso-8859-1';
   CreateAllocator;
   FPackage := APackage;
@@ -577,17 +621,27 @@ begin
   if Length(Package.Name) > 1 then
     begin
     AddPage(Package, 0);
+    AddPage(Package,IndexSubIndex);
     AddTopicPages(Package);
     end;
-
-  for i := 0 to Package.Modules.Count - 1 do
-    ScanModule(TPasModule(Package.Modules[i]));
+  L:=TObjectList.Create;
+  try
+    for i := 0 to Package.Modules.Count - 1 do
+      ScanModule(TPasModule(Package.Modules[i]),L);
+    // Resolve links
+    For I:=0 to L.Count-1 do
+      With TLinkData(L[i]) do
+        Engine.AddLink(FPathName,ResolveLinkIDInUnit(FLink,FModuleName));
+  finally
+    L.Free;
+  end;
 end;
 
 destructor THTMLWriter.Destroy;
 begin
   PageInfos.Free;
   OutputNodeStack.Free;
+  FAllocator.Free;
   inherited Destroy;
 end;
 
@@ -600,8 +654,8 @@ var
 begin
   Doc := THTMLDocument.Create;
   Result := Doc;
-  Doc.AppendChild(Doc.CreateProcessingInstruction(
-    'DOCTYPE', 'HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"'));
+  Doc.AppendChild(Doc.Impl.CreateDocumentType(
+    'HTML', '-//W3C//DTD HTML 4.0 Transitional//EN', ''));
 
   HTMLEl := Doc.CreateHtmlElement;
   Doc.AppendChild(HTMLEl);
@@ -612,7 +666,7 @@ begin
   HeadEl.AppendChild(El);
   El['http-equiv'] := 'Content-Type';
   
-  El['content'] := Format('text/html; charset=%s',[charset]);
+  El['content'] := 'text/html; charset=utf-8';
   TitleElement := Doc.CreateElement('title');
   HeadEl.AppendChild(TitleElement);
   El := Doc.CreateElement('link');
@@ -738,6 +792,14 @@ end;
   - AppendHyperlink (for unresolved parse tree element links)
 }
 
+function THTMLWriter.ResolveLinkIDInUnit(const Name,UnitName: String): DOMString;
+
+begin
+  Result:=ResolveLinkID(Name);
+  If (Result='') and (UnitName<>'')  then
+    Result:=ResolveLinkID(UnitName+'.'+Name);
+end;
+
 function THTMLWriter.ResolveLinkID(const Name: String): DOMString;
 var
   i: Integer;
@@ -762,8 +824,10 @@ begin
       if Length(Result) = 0 then
       begin
         if Assigned(Module) then
+          begin
           Result := Engine.FindAbsoluteLink(Module.PathName + '.' + Name);
-        // WriteLn('Searching for ', Module.PathName + '.' + Name, ' => ', Result);
+//          WriteLn('Searching for ', Module.PathName + '.' + Name, ' => ', Result);
+          end;
         if Length(Result) = 0 then
           for i := Length(Name) downto 1 do
             if Name[i] = '.' then
@@ -829,11 +893,13 @@ begin
   Result := CreateEl(Parent, 'h3');
 end;
 
-function THTMLWriter.CreateTable(Parent: TDOMNode): THTMLElement;
+function THTMLWriter.CreateTable(Parent: TDOMNode; const AClass: DOMString = ''): THTMLElement;
 begin
   Result := CreateEl(Parent, 'table');
   Result['cellspacing'] := '0';
   Result['cellpadding'] := '0';
+  if AClass <> '' then
+    Result['class'] := AClass;
 end;
 
 function THTMLWriter.CreateContentTable(Parent: TDOMNode): THTMLElement;
@@ -883,7 +949,6 @@ begin
   Result['class'] := 'warning';
 end;
 
-
 procedure THTMLWriter.PushOutputNode(ANode: TDOMNode);
 begin
   OutputNodeStack.Add(CurOutputNode);
@@ -931,6 +996,53 @@ begin
   PopOutputNode;
 end;
 
+procedure THTMLWriter.DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString);
+
+Var
+  Pel,Cel,Lel : TDOMNode;
+  El :TDomElement;
+  D : String;
+  L : Integer;
+   
+begin
+  // Determine parent node.
+  If (ACaption='') then
+    Pel:=CurOutputNode
+  else
+    begin
+    Cel:=CreateTable(CurOutputNode, 'imagetable');
+    Pel:=CreateTD(CreateTR(Cel));
+    Cel:=CreateTD(CreateTR(Cel));
+    El := CreateEl(Cel, 'span');
+    El['class'] := 'imagecaption';
+    Cel := El;
+    If (ALinkName<>'') then
+      Cel:=CreateAnchor(Cel,ALinkName);
+    AppendText(Cel,ACaption);
+    end;
+  // Determine URL for image.  
+  D:=BaseImageURL;
+  If (D='') then
+    begin
+    If (Module=Nil) then
+      D:=Allocator.GetRelativePathToTop(Package)
+    else 
+      D:=Allocator.GetRelativePathToTop(Module);
+    L:=Length(D);  
+    If (L>0) and (D[L]<>'/') then
+      D:=D+'/';
+    D:=D+'images/';
+    end
+  else  
+    L:=Length(D);  
+    If (L>0) and (D[L]<>'/') then
+      D:=D+'/';
+  // Create image node.  
+  El:=CreateEl(Pel,'img');
+  EL['src']:=D+AFileName;
+  El['alt']:=ACaption;
+end;
+
 procedure THTMLWriter.DescrWriteFileEl(const AText: DOMString);
 var
   NewEl: TDOMElement;
@@ -1285,16 +1397,28 @@ end;
 
 Procedure THTMLWriter.AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode : TDocNode);
 
+Var
+  N : TDocNode;
+
 begin
-  if Assigned(DocNode) and Assigned(DocNode.ShortDescr) then
+  if Assigned(DocNode) then
     begin
-    PushOutputNode(Parent);
-    try
-      if not ConvertShort(AContext,TDomElement(DocNode.ShortDescr)) then
-        Warning(AContext, SErrInvalidShortDescr)
-    finally
-      PopOutputNode;
-    end;
+    If (DocNode.Link<>'') then
+      begin
+      N:=Engine.FindLinkedNode(DocNode);
+      If (N<>Nil) then
+        DocNode:=N;
+      end;
+    If Assigned(DocNode.ShortDescr) then
+      begin
+      PushOutputNode(Parent);
+      try
+        if not ConvertShort(AContext,TDomElement(DocNode.ShortDescr)) then
+          Warning(AContext, SErrInvalidShortDescr)
+      finally
+        PopOutputNode;
+      end;
+      end;
     end;
 end;
 
@@ -1304,6 +1428,22 @@ begin
   AppendShortDescr(Element,Parent,Engine.FindDocNode(Element));
 end;
 
+procedure THTMLWriter.AppendShortDescrCell(Parent: TDOMNode;
+  Element: TPasElement);
+
+var
+  ParaEl: TDOMElement;
+
+begin
+  if Assigned(Engine.FindShortDescr(Element)) then
+  begin
+    AppendNbSp(CreatePara(CreateTD(Parent)), 2);
+    ParaEl := CreatePara(CreateTD(Parent));
+    ParaEl['class'] := 'cmt';
+    AppendShortDescr(ParaEl, Element);
+  end;
+end;
+
 procedure THTMLWriter.AppendDescr(AContext: TPasElement; Parent: TDOMNode;
   DescrNode: TDOMElement; AutoInsertBlock: Boolean);
 begin
@@ -1330,19 +1470,6 @@ begin
 end;
 
 
-procedure THTMLWriter.AppendShortDescrCell(Parent: TDOMNode;
-  Element: TPasElement);
-var
-  ParaEl: TDOMElement;
-begin
-  if Assigned(Engine.FindShortDescr(Element)) then
-  begin
-    AppendNbSp(CreatePara(CreateTD(Parent)), 2);
-    ParaEl := CreatePara(CreateTD(Parent));
-    ParaEl['class'] := 'cmt';
-    AppendShortDescr(ParaEl, Element);
-  end;
-end;
 
 function THTMLWriter.AppendHyperlink(Parent: TDOMNode;
   Element: TPasElement): TDOMElement;
@@ -1389,7 +1516,9 @@ begin
           end;
         end;
       end;
-    end else
+    end else if Element is TPasEnumValue then
+      s := ResolveLinkID(Element.Parent.PathName)
+    else  
       s := ResolveLinkID(Element.PathName);
 
     if Length(s) > 0 then
@@ -1797,7 +1926,7 @@ begin
   ParaEl := CreateEl(CreateTD(TREl), 'b');
 
   if Assigned(Module) then
-  begin
+    begin
     AddLink(0, SDocOverview);
     if Module.InterfaceSection.ResStrings.Count > 0 then
       AddLink(ResstrSubindex, SDocResStrings);
@@ -1811,7 +1940,20 @@ begin
       AddLink(ProcsSubindex, SDocProceduresAndFunctions);
     if Module.InterfaceSection.Variables.Count > 0 then
       AddLink(VarsSubindex, SDocVariables);
-  end;
+    AddLink(IndexSubIndex,SDocIdentifierIndex);  
+    end
+  else
+    begin
+    // Manually add link for package page
+    AppendText(ParaEl, '[');
+    if (IndexSubIndex = ASubpageIndex) then
+      AppendText(ParaEl, SDocIdentifierIndex)
+    else
+      AppendText(
+        CreateLink(ParaEl, ResolveLinkWithinPackage(Package, IndexSubIndex)),
+        SDocIdentifierIndex);
+    AppendText(ParaEl, ']');
+    end;
 
   if Length(SearchPage) > 0 then
   begin
@@ -2037,7 +2179,13 @@ begin
   BaseDirectory := Allocator.GetRelativePathToTop(AElement);
 
   if AElement.ClassType = TPasPackage then
-    CreatePackagePageBody
+    begin
+    Module:=Nil;
+    If (ASubPageIndex=0) then
+      CreatePackagePageBody
+    else if ASubPageIndex=IndexSubIndex then
+      CreatePackageIndex  
+    end
   else
     begin
     Element := AElement;
@@ -2064,6 +2212,158 @@ begin
   end;
 end;
 
+procedure THTMLWriter.CreateIndexPage(L : TStringList);
+
+Var
+  Lists  : Array['A'..'Z'] of TStringList;
+  LOther : TStringList;
+  
+  CL : TStringList;
+  TableEl, TREl, EL: TDOMElement;
+  E : TPasElement;
+  I,Rows,J,Index : Integer;
+  S : String;
+  C : Char;
+
+begin
+  For C:='A' to 'Z' do
+    Lists[C]:=Nil;
+  L.Sort;
+  Cl:=Nil;
+  // Divide over alphabet
+  For I:=0 to L.Count-1 do
+    begin
+    S:=L[i];
+    E:=TPasElement(L.Objects[i]);
+    If not (E is TPasUnresolvedTypeRef) then
+      begin
+      If (S<>'') then 
+        begin
+        C:=Upcase(S[1]);
+        If C='_' then
+          C:='A';
+        If (C in ['A'..'Z']) and (Lists[C]=Nil) then
+          begin
+          CL:=TStringList.Create;
+          Lists[C]:=CL;
+          end;
+        end;
+      if assigned(cl) then  
+        CL.AddObject(S,E);
+      end;  
+    end;  
+  Try  
+  // Create a quick jump table to all available letters.    
+  TableEl := CreateTable(BodyElement);
+  TableEl['border']:='1';
+  TableEl['width']:='50%';
+  TREl := CreateTR(TableEl);
+  for C:='A' to 'Z' do
+    If (Lists[C]<>Nil) then
+      begin
+      El:=CreateTD_vtop(TREl);
+      AppendText(CreateLink(El,'#SECTION'+C),C);
+      If C<>'Z' then
+       AppendNBsp(El,1);
+      end;
+  // Now emit all identifiers.    
+  TableEl:=Nil;
+  For C:='A' to 'Z' do
+    begin
+    CL:=Lists[C];
+    If CL<>Nil then
+      begin
+      El:=CreateH2(BodyElement);
+      AppendText(El,C);
+      CreateAnchor(El,'SECTION'+C);
+      TableEl := CreateTable(BodyElement);
+      TableEl['Width']:='80%';
+      // Determine number of rows needed
+      Rows:=(CL.Count div IndexColCount);
+      If ((CL.Count Mod IndexColCount)<>0) then
+        Inc(Rows);
+      // Fill rows  
+      For I:=0 to Rows-1 do
+        begin
+        TREl := CreateTR(TableEl);
+        For J:=0 to IndexColCount-1 do 
+          begin
+          El:=CreateTD_vtop(TREl);
+          Index:=(J*Rows)+I;
+          If (Index<CL.Count) then
+            begin
+            S:=CL[Index];
+            E:=TPasElement(CL.Objects[Index]);
+            AppendHyperlink(El,E);
+            end;
+          end;  
+        end;  
+      end; // have List
+    end;  // For C:=
+  Finally
+    for C:='A' to 'Z' do
+      FreeAndNil(Lists[C]);
+  end;  
+end;
+
+procedure THTMLWriter.AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
+
+  Procedure AddElementsFromList(L : TStrings; List : TList);
+  
+  Var
+    I : Integer;
+    El : TPasElement;
+    
+  begin
+    For I:=0 to List.Count-1 do
+      begin
+      El:=TPasElement(List[I]);
+      L.AddObject(El.Name,El);
+      If el is TPasEnumType then
+        AddElementsFromList(L,TPasEnumType(el).Values);
+      end;
+  end;
+  
+begin
+  AddElementsFromList(L,AModule.InterfaceSection.Consts);
+  AddElementsFromList(L,AModule.InterfaceSection.Types);
+  AddElementsFromList(L,AModule.InterfaceSection.Functions);
+  AddElementsFromList(L,AModule.InterfaceSection.Classes);
+  AddElementsFromList(L,AModule.InterfaceSection.Variables);
+  AddElementsFromList(L,AModule.InterfaceSection.ResStrings);
+end;
+
+
+procedure THTMLWriter.CreatePackageIndex;
+
+Var
+  L : TStringList;
+  I : Integer;
+  M : TPasModule;
+  E : TPasElement;
+  S : String;    
+  
+begin
+  L:=TStringList.Create;
+  try
+    L.Capacity:=PageInfos.Count; // Too much, but that doesn't hurt.
+    For I:=0 to Package.Modules.Count-1 do
+      begin
+      M:=TPasModule(Package.Modules[i]);
+      L.AddObject(M.Name,M);
+      AddModuleIdentifiers(M,L);
+      end;
+    AppendMenuBar(IndexSubIndex);
+    S:=Package.Name;
+    If Length(S)>0 then
+      Delete(S,1,1);
+    AppendTitle(Format(SDocPackageIndex, [S]));
+    CreateIndexPage(L);
+  Finally
+    L.Free;
+  end;
+end;
+
 procedure THTMLWriter.CreatePackagePageBody;
 var
   DocNode: TDocNode;
@@ -2137,6 +2437,23 @@ begin
     end;
 end;
 
+procedure THTMLWriter.CreateModuleIndexPage(AModule: TPasModule);
+
+Var
+  L : TStringList;
+
+begin
+  L:=TStringList.Create;
+  try
+    AddModuleIdentifiers(AModule,L);
+    AppendMenuBar(IndexSubIndex);
+    AppendTitle(Format(SDocModuleIndex, [AModule.Name]));
+    CreateIndexPage(L);
+  Finally
+    L.Free;
+  end;  
+end;
+
 procedure THTMLWriter.CreateModulePageBody(AModule: TPasModule;
   ASubpageIndex: Integer);
 
@@ -2246,6 +2563,7 @@ procedure THTMLWriter.CreateModulePageBody(AModule: TPasModule;
       AppendText(ParaEl, Decl.Value);
     end;
   end;
+  
 
 begin
   case ASubpageIndex of
@@ -2263,6 +2581,8 @@ begin
       CreateSimpleSubpage(SDocProceduresAndFunctions, AModule.InterfaceSection.Functions);
     VarsSubindex:
       CreateSimpleSubpage(SDocVariables, AModule.InterfaceSection.Variables);
+    IndexSubIndex: 
+      CreateModuleIndexPage(AModule);
   end;
 end;
 
@@ -2575,6 +2895,12 @@ var
             AppendKw(CodeEl, ' default');
             AppendSym(CodeEl, ';');
           end;
+          if (TPasProperty(Member).ImplementsName<>'') then
+          begin
+            AppendKw(CodeEl, ' implements');
+            AppendText(CodeEl, ' '+TPasProperty(Member).ImplementsName);
+            AppendSym(CodeEl, ';');
+          end;
           SetLength(s, 0);
           if Length(TPasProperty(Member).ReadAccessorName) > 0 then
             s := s + 'r';
@@ -2994,6 +3320,10 @@ begin
     FooterFile := Arg
   else if Cmd = '--charset' then
     CharSet := Arg
+  else if Cmd = '--index-colcount' then
+    IndexColCount := StrToIntDef(Arg,IndexColCount)
+  else if Cmd = '--image-url' then
+    FBaseImageURL  := Arg
   else if Cmd = '--footer-date' then
     begin
     FIDF:=True;
@@ -3015,6 +3345,14 @@ begin
   List.Add(SHTMLUsageFooter);
   List.Add('--footer-date[=Fmt]');
   List.Add(SHTMLUsageFooterDate);
+  List.Add('--charset=set');
+  List.Add(SHTMLUsageCharset);
+  List.Add('--html-search=pagename');
+  List.Add(SHTMLHtmlSearch);
+  List.Add('--index-colcount=N');
+  List.Add(SHTMLIndexColcount);
+  List.Add('--image-url=url');
+  List.Add(SHTMLImageUrl);
 end;
 
 // private methods

+ 4 - 0
utils/fpdoc/dw_htmlchm.inc

@@ -282,6 +282,10 @@ begin
     for i := 0 to Package.Modules.Count - 1 do
     begin
       AModule := TPasModule(Package.Modules[i]);
+      ParentItem := Index.Items.NewItem;
+      ParentItem.Text := AModule.Name;
+      ParentItem.Local := Allocator.GetFilename(AModule, 0);
+
       //  classes
       for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
       begin

+ 28 - 0
utils/fpdoc/dw_latex.pp

@@ -38,6 +38,7 @@ Type
   TLaTeXWriter = class(TLinearWriter)
   protected
     FLink: String;
+    FImageDir: String;
     FTableCount : Integer;
     FInVerbatim : Boolean;
     Inlist,
@@ -85,6 +86,7 @@ Type
     procedure DescrEndItalic; override;
     procedure DescrBeginEmph; override;
     procedure DescrEndEmph; override;
+    procedure DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString); override;
     procedure DescrWriteFileEl(const AText: DOMString); override;
     procedure DescrWriteKeywordEl(const AText: DOMString); override;
     procedure DescrWriteVarEl(const AText: DOMString); override;
@@ -125,6 +127,7 @@ Type
     procedure DescrEndTableCell; override;
     // TFPDocWriter class methods
     Function InterPretOption(Const Cmd,Arg : String) : boolean; override;
+    Property ImageDir : String Read FImageDir Write FImageDir;
   end;
 
 
@@ -215,6 +218,29 @@ begin
   Write('}');
 end;
 
+procedure TLaTeXWriter.DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString); 
+
+Var
+  FN : String;
+  L : Integer;
+  
+begin
+  Writeln('\begin{figure}[ht]%');
+  Writeln('\begin{center}');
+  If (ACaption<>ACaption) then
+    Writeln(Format('\caption{%s}',[EscapeText(ACaption)]));
+  If (ALinkName<>'') then
+    WriteLabel('fig:'+ALinkName);
+  FN:=ImageDir;
+  L:=Length(FN);
+  If (L>0) and (FN[l]<>'/')  then
+    FN:=FN+'/';
+  FN:=FN+AFileName;
+  Writeln('\epsfig{file='+FN+'}');
+  Writeln('\end{center}');
+  Writeln('\end{figure}');
+end;
+
 procedure TLaTeXWriter.DescrWriteFileEl(const AText: DOMString);
 begin
   Write('\file{');
@@ -675,6 +701,8 @@ begin
     LatexHighLight:=True
   else if Cmd = '--latex-extension' then
      TexExtension:=Arg
+  else if Cmd = '--image-dir' then
+     ImageDir:=Arg
   else
     Result:=False;
 end;

+ 35 - 5
utils/fpdoc/dwriter.pp

@@ -69,10 +69,10 @@ type
   private
     FEngine  : TFPDocEngine;
     FPackage : TPasPackage;
-
     FTopics  : TList;
+    FImgExt : String;
+    
   protected
-
     procedure Warning(AContext: TPasElement; const AMsg: String);
     procedure Warning(AContext: TPasElement; const AMsg: String;
       const Args: array of const);
@@ -96,7 +96,8 @@ type
       Node: TDOMNode);
     function ConvertSimpleBlock(AContext: TPasElement; Node: TDOMNode): Boolean;
     Function FindTopicElement(Node : TDocNode): TTopicElement;
-
+    Procedure ConvertImage(El : TDomElement);
+    
     procedure DescrWriteText(const AText: DOMString); virtual; abstract;
     procedure DescrBeginBold; virtual; abstract;
     procedure DescrEndBold; virtual; abstract;
@@ -104,6 +105,7 @@ type
     procedure DescrEndItalic; virtual; abstract;
     procedure DescrBeginEmph; virtual; abstract;
     procedure DescrEndEmph; virtual; abstract;
+    procedure DescrWriteImageEl(const AFileName, ACaption,ALinkName : DOMString); virtual; 
     procedure DescrWriteFileEl(const AText: DOMString); virtual; abstract;
     procedure DescrWriteKeywordEl(const AText: DOMString); virtual; abstract;
     procedure DescrWriteVarEl(const AText: DOMString); virtual; abstract;
@@ -148,6 +150,7 @@ type
     property Engine : TFPDocEngine read FEngine;
     Property Package : TPasPackage read FPackage;
     Property Topics : TList Read FTopics;
+    Property ImageExtension : String Read FImgExt Write FImgExt;
     // Should return True if option was succesfully interpreted.
     Function InterpretOption(Const Cmd,Arg : String) : Boolean; Virtual;
     Class Procedure Usage(List : TStrings); virtual;
@@ -320,6 +323,7 @@ begin
   FEngine  := AEngine;
   FPackage := APackage;
   FTopics:=Tlist.Create;
+  FImgExt:='.png';
 end;
 
 destructor TFPDocWriter.Destroy;
@@ -360,6 +364,12 @@ begin
     end;
 end;
 
+Procedure TFPDocWriter.DescrWriteImageEl(const AFileName, ACaption,ALinkName : DOMString); 
+
+begin
+  system.writeln(ClassName,': No support for images yet: ',AFileName,' (caption: "',ACaption,'")');
+end;
+
 { ---------------------------------------------------------------------
   Generic documentation node conversion
   ---------------------------------------------------------------------}
@@ -460,7 +470,7 @@ function TFPDocWriter.ConvertBaseShort(AContext: TPasElement;
 
   function ConvertText: DOMString;
   var
-    s: String;
+    s: DOMString;
     i: Integer;
   begin
     if Node.NodeType = TEXT_NODE then
@@ -971,10 +981,30 @@ begin
     ConvertDefinitionList;
     DescrEndDefinitionList;
     Result := True;
-  end else
+  end else if Node.NodeName = 'img' then
+  begin
+    begin
+    ConvertImage(Node as TDomElement);
+    Result:=True;
+    end;
+  end else  
     Result := False;
 end;
 
+Procedure TFPDocWriter.ConvertImage(El : TDomElement);
+
+Var
+  FN,Cap,LinkName : DOMString;
+
+begin
+  FN:=El['file'];
+  Cap:=El['caption'];
+  LinkName:=El['name'];
+  FN:=ChangeFileExt(FN,ImageExtension);
+  DescrWriteImageEl(FN,Cap,LinkName);
+end;
+
+
 Constructor TTopicElement.Create(const AName: String; AParent: TPasElement);
 
 begin

+ 51 - 0
utils/fpdoc/fpclasschart.lpi

@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <PathDelim Value="/"/>
+    <Version Value="6"/>
+    <General>
+      <Flags>
+        <SaveOnlyProjectUnits Value="True"/>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <TargetFileExt Value=""/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="fpclasschart.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="fpclasschart"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="dglobals.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dGlobals"/>
+      </Unit1>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="8"/>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 763 - 0
utils/fpdoc/fpclasschart.pp

@@ -0,0 +1,763 @@
+{
+
+    FPClass chart -  Free Pascal class chart generation tool
+    Copyright (c) 2008 - Michael Van Canneyt, [email protected]
+
+    * Free Pascal class chart generation tool
+
+    See the file COPYING, 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+}
+
+program fpclasschart;
+
+uses
+  SysUtils, Classes, Typinfo, Gettext, dom, xmlread,
+  dGlobals, PasTree, PParser,PScanner, xmlwrite;
+
+resourcestring
+  STitle = 'fpClassTree - Create class tree from pascal sources';
+  SVersion = 'Version %s [%s]';
+  SCopyright = '(c) 2008 - Michael Van Canneyt, [email protected]';
+  SCmdLineHelp = 'See documentation for usage.';
+  SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
+  SDone = 'Done.';
+  SSkipMerge = 'Cannot merge %s into %s tree.';
+  SErrNoSuchMergeFile = 'Merge file %s does not exist.';
+  SMergedFile = 'Merged %d classes from file %s.';
+  SClassesAdded = 'Added %d classes from %d files.';
+
+Const
+  RootNames : Array[TPasObjKind] of string
+            = ('Objects', 'Classes', 'Interfaces');
+
+type
+
+  { TClassTreeEngine }
+
+  TClassTreeEngine = class(TFPDocEngine)
+  Private
+    FClassTree : TXMLDocument;
+    FTreeStart : TDomElement;
+    FObjects : TStringList;
+    FObjectKind : TPasObjKind;
+    FParentObject : TPasClassType;
+    function LookForElement(PE: TDomElement; AElement: TPasElement): TDomNode;
+    function NodeMatch(N: TDomNode; AElement: TPasElement): Boolean;
+    Function AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
+  public
+    Constructor Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind);
+    Destructor Destroy; override;
+    Function BuildTree : Integer;
+    function CreateElement(AClass: TPTreeElement; const AName: String;
+      AParent: TPasElement; AVisibility :TPasMemberVisibility;
+      const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override;
+  end;
+
+  { TClassChartFormatter }
+  TClassMode = (cmNormal,cmSubClass,cmheadClass,cmFirstClass);
+  TClassChartFormatter = Class (TObject)
+  private
+    FClassMode: TClassMode;
+    FClassTree: TXMLDocument;
+    FCurrentColCount: Integer;
+    FCurrentRowCount: Integer;
+    FFileName: String;
+    FLargeHeadClassObjects: TStrings;
+    FLevel: Integer;
+    FMaxObjectsPerColumn: Integer;
+    FStartColumnObjects: TStrings;
+  Protected
+    procedure FirstClass(E : TDomElement); virtual;
+    procedure DoEmitClass(E : TDomElement); virtual;
+    procedure DoHeadClass(E: TDomElement); virtual;
+    procedure DoNextColumn(E: TDomElement); virtual;
+    procedure EndSubClass(E: TDomElement; HasSiblings : Boolean); virtual;
+    procedure StartSubClass(E: TDomElement); virtual;
+    Procedure StartChart; virtual;
+    Procedure EndChart; virtual;
+    procedure EmitClass(E : TDomElement; HasSiblings : Boolean);
+  Public
+    Constructor Create (AXML : TXMLDocument); virtual;
+    Destructor Destroy; override;
+    Procedure CreateChart;
+    Property CurrentColCount : Integer Read FCurrentColCount;
+    Property CurrentRowCount : Integer Read FCurrentRowCount;
+    Property ClassTree : TXMLDocument Read FClassTree;
+    Property Level : Integer Read FLevel Write FLevel;
+    Property ClassMode : TClassMode Read FClassMode;
+  Published
+    Property FileName : String Read FFileName Write FFilename;
+    Property StartColumnObjects : TStrings Read FStartColumnObjects;
+    Property LargeHeadClassObjects : TStrings Read FLargeHeadClassObjects;
+    Property MaxObjectsPerColumn : Integer Read FMaxObjectsPerColumn Write FMaxObjectsPerColumn;
+  end;
+
+{ TChartFormatter }
+
+constructor TClassChartFormatter.Create(AXML: TXMLDocument);
+begin
+  FClassTree:=AXML;
+  MaxObjectsPerColumn:=60;
+  FStartColumnObjects:=TStringList.Create;
+  FLargeHeadClassObjects:=TStringList.Create;
+  FLargeHeadClassObjects.Add('TPersistent');
+  FLargeHeadClassObjects.Add('TComponent');
+end;
+
+destructor TClassChartFormatter.Destroy;
+begin
+  FreeAndNil(FStartColumnObjects);
+  FreeAndNil(FLargeHeadClassObjects);
+  Inherited;
+end;
+
+procedure TClassChartFormatter.CreateChart;
+
+Var
+  N : TDomNode;
+  E : TDomElement;
+  I : Integer;
+  L : TFPList;
+
+begin
+  (FStartColumnObjects as TStringList).Sorted:=False;
+  (FLargeHeadClassObjects as TStringList).Sorted:=False;
+  StartChart;
+  try
+    N:=FClassTree.DocumentElement.FirstChild;
+    FCurrentColCount:=0;
+    FCurrentRowCount:=0;
+    FLevel:=0;
+    L:=TFPList.Create;
+    try
+      While (N<>nil) do
+        begin
+        If (N.NodeType=ELEMENT_NODE) then
+          L.Add(N);
+        N:=N.NextSibling;
+        end;
+      If (L.Count>0) then
+        begin
+        FirstClass(TDomElement(L[0]));
+        For I:=0 to L.Count-1 do
+          EmitClass(TDomElement(L[i]),I<L.Count-1);
+        end;
+    finally
+      L.Free;
+    end;
+    L:=TFPList.Create;
+    try
+      For I:=0 to FLargeHeadClassObjects.Count-1 do
+        If Assigned(FLargeHeadClassObjects.Objects[i]) then
+          L.Add(FLargeHeadClassObjects.Objects[i]);
+      FLargeHeadClassObjects.Clear;
+      For I:=0 to L.Count-1 do
+        begin
+        E:= TDomElement(L[i]);
+        DoHeadClass(E);
+        EmitClass(E,I<L.Count-1);
+        end;
+    finally
+      L.Free;
+    end;
+  finally
+    EndChart;
+  end;
+end;
+
+procedure TClassChartFormatter.FirstClass(E : TDomElement);
+
+begin
+  FClassMode:=cmFirstClass;
+end;
+
+procedure TClassChartFormatter.DoEmitClass(E : TDomElement);
+begin
+  //Reset
+  FClassMode:=cmNormal;
+end;
+
+procedure TClassChartFormatter.DoHeadClass(E : TDomElement);
+begin
+  DoNextColumn(E);
+  FClassMode:=cmHeadClass;
+  // Do nothing
+end;
+
+procedure TClassChartFormatter.StartSubClass(E : TDomElement);
+begin
+  FClassMode:=cmSubClass;
+end;
+
+procedure TClassChartFormatter.EndSubClass(E : TDomElement; HasSiblings : Boolean);
+begin
+  FClassMode:=cmNormal;
+end;
+
+procedure TClassChartFormatter.DoNextColumn(E : TDomElement);
+
+begin
+  Inc(FCurrentColCount);
+  FCurrentRowCount:=0;
+end;
+
+procedure TClassChartFormatter.StartChart;
+begin
+  // Do nothing
+end;
+
+procedure TClassChartFormatter.EndChart;
+begin
+  // Do nothing
+end;
+
+procedure TClassChartFormatter.EmitClass(E : TDomElement; HasSiblings: Boolean);
+
+Var
+  DidSub : Boolean;
+  N : TDomNode;
+  I : Integer;
+  L : TFPList;
+
+begin
+  Inc(Flevel);
+  try
+    I:=FStartColumnObjects.IndexOf(E.NodeName);
+    if (-1<>I) or ((FCurrentRowCount>MaxObjectsPerColumn) and (FLevel=2)) then
+      DoNextColumn(E)
+    else
+      begin
+      I:=FLargeHeadClassObjects.IndexOf(E.NodeName);
+      if (-1<>I) then
+        begin
+        FLargeHeadClassObjects.Objects[i]:=E;
+        Exit; // Must be picked up later.
+        end;
+      end;
+    DoEmitClass(E);
+    N:=E.FirstChild;
+    DidSub:=False;
+    L:=TFPList.Create;
+    try
+      While (N<>Nil) do
+        begin
+        if (N.NodeType=ELEMENT_NODE) then
+           L.Add(N);
+        N:=N.NextSibling;
+        end;
+      If L.Count>0 then
+        begin
+        StartSubClass(TDomElement(L[0]));
+        For I:=0 to L.Count-1 do
+          begin
+          EmitClass(TDomElement(L[i]),I<L.Count-1);
+          FClassMode:=cmNormal;
+          end;
+        EndSubClass(E,HasSiblings);
+        end;
+    Finally
+      L.Free;
+    end;
+    Inc(FCurrentRowCount);
+  finally
+    Dec(Flevel);
+  end;
+end;
+
+Type
+
+  { TPostScriptClassChartFormatter }
+
+  TPostScriptClassChartFormatter = Class(TClassChartFormatter)
+    FFile : Text;
+    FMode : TClassMode;
+    FIndent : Integer;
+    Procedure EmitLine(S : String);
+  Protected
+    procedure DoEmitClass(E : TDomElement); override;
+    procedure DoNextColumn(E: TDomElement); override;
+    procedure DoHeadClass(E: TDomElement); override;
+    procedure StartSubClass(E: TDomElement); override;
+    procedure EndSubClass(E: TDomElement; HasSiblings : Boolean); override;
+    Procedure StartChart; override;
+    Procedure EndChart; override;
+  end;
+
+{ TPostScriptClassChartFormatter }
+
+procedure TPostScriptClassChartFormatter.EmitLine(S: String);
+begin
+  Writeln(FFile,StringofChar(' ',Findent*2),S);
+end;
+
+procedure TPostScriptClassChartFormatter.DoEmitClass(E: TDomElement);
+begin
+  Case ClassMode of
+    cmFirstClass : EmitLine(Format('(%s) Ready drawlargebox',[E.NodeName]));
+    cmNormal     : EmitLine(Format('(%s) Ready newclass',[E.NodeName]));
+    cmSubClass   : EmitLine(Format('(%s) Ready newchildclass',[E.NodeName]));
+    cmHeadClass  : EmitLine(Format('(%s) Ready newlargeheadclass',[E.NodeName]));
+  end;
+end;
+
+procedure TPostScriptClassChartFormatter.DoNextColumn(E: TDomElement);
+begin
+  Inherited;
+  FIndent:=0;
+  EmitLine('newcolumn');
+
+end;
+
+procedure TPostScriptClassChartFormatter.DoHeadClass(E: TDomElement);
+begin
+//  DoNextColumn(E);
+  inherited DoHeadClass(E);
+end;
+
+
+procedure TPostScriptClassChartFormatter.EndSubClass(E: TDomElement; HasSiblings : Boolean);
+begin
+  if HasSiblings then
+    EmitLine('onelevelback')
+  else
+    EmitLine('onelevelbackempty');
+  If FIndent>0 then
+    Dec(Findent);
+end;
+
+procedure TPostScriptClassChartFormatter.StartSubClass(E: TDomElement);
+begin
+  inherited StartSubClass(E);
+  Inc(Findent);
+end;
+
+procedure TPostScriptClassChartFormatter.StartChart;
+begin
+  Assign(FFile,FileName);
+  Rewrite(FFile);
+end;
+
+procedure TPostScriptClassChartFormatter.EndChart;
+begin
+  Close(FFile);
+end;
+
+Type
+  TOutputFormat = (ofxml,ofPostscript);
+
+Var
+  OutputFormat : TOutputFormat = ofXML;
+
+const
+  OSTarget: String = {$I %FPCTARGETOS%};
+  CPUTarget: String = {$I %FPCTARGETCPU%};
+  FPCVersion: String = {$I %FPCVERSION%};
+  FPCDate: String = {$I %FPCDATE%};
+
+  
+
+function TClassTreeEngine.CreateElement(AClass: TPTreeElement; const AName: String;
+  AParent: TPasElement; AVisibility : TPasMemberVisibility;
+  const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
+
+Var
+  DN : TDocNode;
+
+begin
+  Result := AClass.Create(AName, AParent);
+  Result.Visibility:=AVisibility;
+  if AClass.InheritsFrom(TPasModule) then
+    CurModule := TPasModule(Result);
+  If AClass.InheritsFrom(TPasClassType) then
+    FObjects.AddObject(AName,Result);
+end;
+
+Constructor TClassTreeEngine.Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind);
+
+Var
+  N : TDomNode;
+
+begin
+  FClassTree:=AClassTree;
+  FTreeStart:=FClassTree.DocumentElement;
+  FPackage:=TPasPackage.Create('dummy',Nil);
+  FObjectKind:=AObjectKind;
+  FObjects:=TStringList.Create;
+  Case FObjectkind of
+    okObject    : FParentObject:=TPasClassType.Create('TObject',FPackage);
+    okClass     : FParentObject:=TPasClassType.Create('TObject',FPackage);
+    okInterface : FParentObject:=TPasClassType.Create('IInterface',FPackage);
+  end;
+  FParentObject.ObjKind:=FObjectKind;
+  Inherited Create;
+end;
+
+destructor TClassTreeEngine.Destroy;
+begin
+  FreeAndNil(FObjects);
+  inherited Destroy;
+end;
+
+Function TClassTreeEngine.BuildTree : Integer;
+
+Var
+  I : Integer;
+  PC : TPasClassType;
+
+begin
+  Result:=0;
+  FObjects.Sorted:=True;
+  For I:=0 to FObjects.Count-1 do
+    begin
+    PC:=TPasClassType(FObjects.Objects[i]);
+    If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
+      AddToClassTree(PC as TPasElement,Result)
+    end;
+end;
+
+Function TClassTreeEngine.NodeMatch(N : TDomNode; AElement : TPasElement) : Boolean;
+
+begin
+  Result:=(N.NodeType=ELEMENT_NODE) and (CompareText(N.NodeName,AElement.Name)=0)
+end;
+
+Function TClassTreeEngine.LookForElement(PE : TDomElement; AElement : TPasElement) : TDomNode;
+
+Var
+  N : TDomNode;
+
+begin
+  Result:=PE.FirstChild;
+  While (Result<>Nil) and Not NodeMatch(Result,AElement) do
+    Result:=Result.NextSibling;
+  If (Result=Nil) then
+    begin
+    N:=PE.FirstChild;
+    While (Result=Nil) and (N<>Nil) do
+      begin
+      if (N.NodeType=ELEMENT_NODE) then
+        begin
+        Result:=LookForElement(N as TDomElement,AElement);
+        end;
+      N:=N.NextSibling;
+      end;
+    end
+end;
+
+Function TClassTreeEngine.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
+
+Var
+  PC : TPasClassType;
+  PE : TDomElement;
+  M : TPasModule;
+  N : TDomNode;
+
+begin
+  PE:=Nil;
+  If (AElement is TPasClassType) then
+    begin
+    PC:=AElement as TPasClassType;
+    If not Assigned(PC.AncestorType) and (CompareText(PC.Name,FParentObject.Name)<>0) then
+      PC.AncestorType:=FParentObject;
+    If Assigned(PC.AncestorType) then
+      PE:=AddToClassTree(PC.AncestorType,ACount);
+    end;
+  If (PE=Nil) then
+    PE:=FTreeStart;
+  N:=LookForElement(PE,AElement);
+  If (N<>Nil) then
+    Result:=N as TDomElement
+  else
+    begin
+    Inc(ACount);
+    Result:=FClassTree.CreateElement(AElement.Name);
+    If Not (AElement is TPasUnresolvedTypeRef) then
+      begin
+      M:=AElement.GetModule;
+      if Assigned(M) then
+        Result['unit']:=M.Name;
+      end;
+    PE.AppendChild(Result);
+    end;
+end;    
+    
+{ ---------------------------------------------------------------------
+  Main program. Document all units.    
+  ---------------------------------------------------------------------}
+
+Function MergeNodes(Doc : TXMLDocument;Dest,Source : TDomElement) : Integer;
+
+Var
+  N : TDomNode;
+  S,E : TDomElement;
+
+
+begin
+  N:=Source.FirstChild;
+  While (N<>Nil) do
+    begin
+    if (N.NodeType=ELEMENT_NODE) then
+      begin
+      S:=N as TDomElement;
+      E:=Dest.FindNode(N.NodeName) as TDomElement;
+      If (E=Nil) then
+        begin
+        E:=Doc.CreateElement(N.NodeName);
+        If S['unit']<>'' then
+          E['Unit']:=S['unit'];
+        Dest.AppendChild(E);
+        Inc(Result);
+        end;
+      Result:=Result+MergeNodes(Doc,E,S);
+      end;
+    N:=N.NextSibling;
+    end;
+end;
+
+Function MergeTrees (Dest,Source : TXMLDocument) : Integer;
+
+Var
+  S,D : TDomElement;
+  Count : Integer;
+
+begin
+  Result:=0;
+  D:=Dest.DocumentElement;
+  S:=Source.DocumentElement;
+  If (S.NodeName=D.NodeName) then
+    Result:=MergeNodes(Dest,D,S)
+  else
+    Writeln(StdErr,Format(SSkipMerge,[S.NodeName,D.NodeName]));
+end;
+  
+Function AnalyseFiles(Const AOutputName : String; InputFiles,MergeFiles : TStrings; AObjectKind : TPasObjKind) : String;
+
+
+Var
+  XML,XML2 : TXMLDocument;
+  I,ACount : Integer;
+  Engine: TClassTreeEngine;
+
+begin
+  XML:=TXMLDocument.Create;
+  Try
+    //XML.
+    XML.AppendChild(XML.CreateElement(RootNames[AObjectKind]));
+    For I:=0 to MergeFiles.Count-1 do
+      begin
+      XMl2:=TXMLDocument.Create;
+      ReadXMLFile(XML2,MergeFiles[i]);
+      try
+        ACount:=MergeTrees(XML,XML2);
+        WriteLn(StdErr,Format(SMergedFile,[ACount,MergeFiles[i]]));
+      Finally
+        FreeAndNil(XML2);
+      end;
+      end;
+    ACount:=0;
+    For I:=0 to InputFiles.Count-1 do
+      begin
+      Engine := TClassTreeEngine.Create(XML,AObjectKind);
+      Try
+        ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget);
+        ACount:=ACount+Engine.BuildTree;
+      Finally
+        Engine.Free;
+      end;
+      end;
+    Case OutputFormat of
+      ofXML :
+        WriteXMlFile(XML,AOutputName);
+      ofPostScript :
+        With TPostScriptClassChartFormatter.Create(XML) do
+          try
+            FileName:=AOutputName;
+            CreateChart;
+          finally
+            Free;
+          end;
+    end;
+    Writeln(StdErr,Format(SClassesAdded,[ACount,InputFiles.Count]));
+  Finally
+    XML.Free;
+  end;
+end;
+
+{ ---------------------------------------------------------------------
+    Option management
+  ---------------------------------------------------------------------}
+
+
+var  
+  cmdObjectKind : TPasObjKind;
+  InputFiles, 
+  MergeFiles : TStringList;
+  DocLang : String;
+  PackageName, 
+  OutputName: String;
+
+procedure InitOptions;
+begin
+  InputFiles := TStringList.Create;
+  MergeFiles := TStringList.Create;
+end;
+
+procedure FreeOptions;
+
+begin
+  MergeFiles.Free;
+  InputFiles.Free;
+end;
+
+{ ---------------------------------------------------------------------
+  Usage  
+  ---------------------------------------------------------------------}
+  
+Procedure Usage;
+
+begin
+  Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
+  Writeln('Where [options] is one or more of :');
+  Writeln(' --merge=filename    Filename with object tree to merge.');
+  Writeln(' --help              Emit help.');
+  Writeln(' --input=cmdline     Input file to create skeleton for.');
+  Writeln('                     Use options are as for compiler.');
+  Writeln(' --kind=objectkind   Specify object kind. One of object, class, interface.');
+  Writeln(' --lang=language     Use selected language.');
+  Writeln(' --output=filename   Send output to file.');
+end;
+
+procedure ParseOption(const s: String);
+
+  procedure AddToFileList(List: TStringList; const FileName: String);
+  var
+    f: Text;
+    s: String;
+  begin
+    if Copy(FileName, 1, 1) = '@' then
+    begin
+      Assign(f, Copy(FileName, 2, Length(FileName)));
+      Reset(f);
+      while not EOF(f) do
+      begin
+        ReadLn(f, s);
+        List.Add(s);
+      end;
+      Close(f);
+    end else
+      List.Add(FileName);
+  end;
+
+var
+  i: Integer;
+  Cmd, Arg: String;
+begin
+  cmdObjectKind:=okClass;
+  if (s = '-h') or (s = '--help') then
+    begin
+    Usage;
+    Halt(0);
+    end;
+  i := Pos('=', s);
+  if i > 0 then
+  begin
+    Cmd := Copy(s, 1, i - 1);
+    Arg := Copy(s, i + 1, Length(s));
+  end else
+  begin
+    Cmd := s;
+    SetLength(Arg, 0);
+  end;
+  if (Cmd = '-i') or (Cmd = '--input') then
+    AddToFileList(InputFiles, Arg)
+  else if (Cmd = '-l') or (Cmd = '--lang') then
+    DocLang := Arg
+  else if (Cmd = '-o') or (Cmd = '--output') then
+    OutputName := Arg
+  else if (Cmd = '-k') or (Cmd = '--kind') then
+    cmdObjectKind:=TPasObjKind(GetEnumValue(TypeInfo(TPasObjKind),'ok'+Arg))
+  else if (Cmd = '-f') or (Cmd = '--format') then
+    OutputFormat:=TOutputFormat(GetEnumValue(TypeInfo(TOutputFormat),'of'+Arg))
+  else if Cmd = '--merge' then
+    begin
+    if FileExists(Arg) then
+      MergeFiles.Add(Arg)
+    else
+      Writeln(StdErr,Format(SErrNoSuchMergeFile,[arg]));
+    end
+  else
+    begin
+    WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
+    Usage;
+    Halt(1);
+    end;
+end;
+
+Function ParseCommandLine : Integer;
+
+Const
+{$IFDEF Unix}
+  MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
+{$ELSE}
+  MoFileTemplate ='intl/makeskel.%s.mo';
+{$ENDIF}
+
+var
+  MOFilename: string;
+  i: Integer;
+
+begin
+  Result:=0;
+  DocLang:='';
+  for i := 1 to ParamCount do
+    ParseOption(ParamStr(i));
+  If (DocLang<>'') then
+    begin
+    MOFilename:=Format(MOFileTemplate,[DocLang]);
+    if FileExists(MOFilename) then
+      gettext.TranslateResourceStrings(MoFileName)
+    else
+      writeln('NOTE: unable to find tranlation file ',MOFilename);
+    // Translate internal documentation strings
+    TranslateDocStrings(DocLang);
+    end;
+end;
+
+
+{ ---------------------------------------------------------------------
+  Main Program  
+  ---------------------------------------------------------------------}
+  
+Procedure Run;
+  
+var
+  E: Integer;
+
+begin
+  WriteLn(STitle);
+  WriteLn(Format(SVersion, [FPCVersion, FPCDate]));
+  WriteLn(SCopyright);
+  InitOptions;
+  Try
+    E:=ParseCommandLine;
+    If E<>0 then
+      Halt(E);
+    WriteLn;
+    AnalyseFiles(OutputName,InputFiles,MergeFiles,cmdObjectKind);
+    WriteLn(StdErr,SDone);
+  Finally  
+    FreeOptions;
+  end;  
+end;
+
+Begin
+  Run;  
+end.
+

+ 97 - 0
utils/fpdoc/fpdoc.lpi

@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <PathDelim Value="/"/>
+    <Version Value="6"/>
+    <General>
+      <Flags>
+        <SaveOnlyProjectUnits Value="True"/>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <IconPath Value="./"/>
+      <TargetFileExt Value=""/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <Units Count="11">
+      <Unit0>
+        <Filename Value="fpdoc.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="FPDoc"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="dwriter.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dWriter"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="dwlinear.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dwlinear"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="dw_latex.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_LaTeX"/>
+      </Unit3>
+      <Unit4>
+        <Filename Value="dw_xml.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_XML"/>
+      </Unit4>
+      <Unit5>
+        <Filename Value="dw_html.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_HTML"/>
+      </Unit5>
+      <Unit6>
+        <Filename Value="dw_ipf.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_IPF"/>
+      </Unit6>
+      <Unit7>
+        <Filename Value="dw_man.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_man"/>
+      </Unit7>
+      <Unit8>
+        <Filename Value="dw_linrtf.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_LinRTF"/>
+      </Unit8>
+      <Unit9>
+        <Filename Value="dw_txt.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dw_txt"/>
+      </Unit9>
+      <Unit10>
+        <Filename Value="dglobals.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dGlobals"/>
+      </Unit10>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="8"/>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 78 - 0
utils/fpdoc/makeskel.lpi

@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <PathDelim Value="/"/>
+    <Version Value="6"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <MainUnit Value="0"/>
+      <TargetFileExt Value=""/>
+      <ActiveEditorIndexAtStart Value="1"/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+      <Language Value=""/>
+      <CharSet Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="makeskel.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="MakeSkel"/>
+        <CursorPos X="8" Y="22"/>
+        <TopLine Value="1"/>
+        <EditorIndex Value="0"/>
+        <UsageCount Value="20"/>
+        <Loaded Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="dglobals.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dGlobals"/>
+        <CursorPos X="40" Y="311"/>
+        <TopLine Value="300"/>
+        <EditorIndex Value="1"/>
+        <UsageCount Value="20"/>
+        <Loaded Value="True"/>
+      </Unit1>
+    </Units>
+    <JumpHistory Count="1" HistoryIndex="0">
+      <Position1>
+        <Filename Value="makeskel.pp"/>
+        <Caret Line="22" Column="8" TopLine="1"/>
+      </Position1>
+    </JumpHistory>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="8"/>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="2">
+      <Item1>
+        <Name Value="ECodetoolError"/>
+      </Item1>
+      <Item2>
+        <Name Value="EFOpenError"/>
+      </Item2>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 338 - 206
utils/fpdoc/makeskel.pp

@@ -36,16 +36,35 @@ resourcestring
 type
   TCmdLineAction = (actionHelp, actionConvert);
 
+  TNodePair = Class(TObject)
+  Private
+    FEl : TPasElement;
+    FNode : TDocNode;
+  Public  
+    Constructor Create(AnElement : TPasElement; ADocNode : TDocNode);
+    Property Element : TPasElement Read FEl;
+    Property DocNode : TDocNode Read FNode;
+  end;
+
   TSkelEngine = class(TFPDocEngine)
+  Private
+    FEmittedList, 
+    FNodeList,
     FModules : TStringList;
     Procedure  DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
   public
     Destructor Destroy; override;
+    Function MustWriteElement(El : TPasElement; Full : Boolean) : Boolean;
+    Function WriteElement(Var F : Text; El : TPasElement; ADocNode : TDocNode) : Boolean;
     function FindModule(const AName: String): TPasModule; override;
     function CreateElement(AClass: TPTreeElement; const AName: String;
       AParent: TPasElement; AVisibility :TPasMemberVisibility;
       const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override;
     procedure WriteUnReferencedNodes;
+    Procedure WriteNodes(Var F : Text; AModule : TPasModule; List : TStrings);
+    Procedure DocumentFile(Var F : Text; Const AFileName,ATarget,ACPU : String);
+    Property NodeList : TStringList Read FNodeList;
+    Property EmittedList : TStringList Read FEmittedList;
   end;
 
 const
@@ -56,20 +75,25 @@ const
   FPCDate: String = {$I %FPCDATE%};
 
 var
-  EmittedList, InputFiles, DescrFiles: TStringList;
-  DocLang: String;
-  Engine: TSkelEngine;
+  WriteDeclaration,
   UpdateMode,
+  SortNodes,
+  DisableOverride,
   DisableErrors,
   DisableSeealso,
   DisableArguments,
   DisableProtected,
   DisablePrivate,
   DisableFunctionResults: Boolean;
-
   EmitClassSeparator: Boolean;
-  PackageName, OutputName: String;
-  f: Text;
+  
+  
+Constructor TNodePair.Create(AnElement : TPasElement; ADocNode : TDocNode);
+
+begin
+  Fel:=Anelement;
+  FNode:=ADocNode;
+end;
 
 function TSkelEngine.FindModule(const AName: String): TPasModule; 
 
@@ -110,50 +134,73 @@ begin
     end;
 end;
 
+Function TSkelEngine.MustWriteElement(El : TPasElement; Full : Boolean) : Boolean;
+
+Var
+  ParentVisible:Boolean;
+  PT,PP : TPasElement;
+begin
+  ParentVisible:=True;
+  If (El is TPasArgument) or (El is TPasResultElement) then
+    begin
+    PT:=El.Parent;
+    // Skip ProcedureType or PasFunctionType
+    If (PT<>Nil) then
+      begin
+      if (PT is TPasProcedureType) or (PT is TPasFunctionType) then
+        PT:=PT.Parent;
+      If (PT<>Nil) and ((PT is TPasProcedure) or (PT is TPasProcedure))   then
+        PP:=PT.Parent
+      else
+        PP:=Nil;
+      If (PP<>Nil) and (PP is TPasClassType) then
+        begin
+        ParentVisible:=((not DisablePrivate or (PT.Visibility<>visPrivate)) and
+                       (not DisableProtected or (PT.Visibility<>visProtected)));
+        end;
+      end;
+    end;
+  Result:=Assigned(El.Parent) and (Length(El.Name) > 0) and
+          (ParentVisible and (not DisableArguments or (El.ClassType <> TPasArgument))) and
+          (ParentVisible and (not DisableFunctionResults or (El.ClassType <> TPasResultElement))) and
+          (not DisablePrivate or (el.Visibility<>visPrivate)) and
+          (not DisableProtected or (el.Visibility<>visProtected));
+  If Result and Full then
+    begin
+    Result:=(Not Assigned(FEmittedList) or (FEmittedList.IndexOf(El.FullName)=-1));
+    If DisableOverride and (El is TPasProcedure) then
+      Result:=Not TPasProcedure(El).IsOverride;
+    end;  
+end;
+
 
 function TSkelEngine.CreateElement(AClass: TPTreeElement; const AName: String;
   AParent: TPasElement; AVisibility : TPasMemberVisibility;
   const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
 
-  Function WriteThisNode(APasElement : TPasElement; DocNode : TDocNode)  : Boolean;
+Var
+  DN : TDocNode;
 
-  Var
-    ParentVisible:Boolean;
-    PT,PP : TPasElement;
-  begin
-    ParentVisible:=True;
-    If (APasElement is TPasArgument) or (APasElement is TPasResultElement) then
-      begin
-      PT:=AParent;
-      // Skip ProcedureType or PasFunctionType
-      If (PT<>Nil) then
-        begin
-        if (PT is TPasProcedureType) or (PT is TPasFunctionType) then
-          PT:=PT.Parent;
-        If (PT<>Nil) and ((PT is TPasProcedure) or (PT is TPasProcedure))   then
-          PP:=PT.Parent
-        else
-          PP:=Nil;
-        If (PP<>Nil) and (PP is TPasClassType) then
-          begin
-          ParentVisible:=((not DisablePrivate or (PT.Visibility<>visPrivate)) and
-                         (not DisableProtected or (PT.Visibility<>visProtected)));
-          end;
-        end;
-      end;
-    Result:=Assigned(AParent) and (Length(AName) > 0) and
-            (ParentVisible and (not DisableArguments or (APasElement.ClassType <> TPasArgument))) and
-            (ParentVisible and (not DisableFunctionResults or (APasElement.ClassType <> TPasResultElement))) and
-            (not DisablePrivate or (AVisibility<>visPrivate)) and
-            (not DisableProtected or (AVisibility<>visProtected)) and
-            (Not Assigned(EmittedList) or (EmittedList.IndexOf(APasElement.FullName)=-1));
-    If Result and updateMode then
-      begin
-      Result:=DocNode=Nil;
-      If Result then
-        Writeln(stderr,Format(ScreatingNewNode,[APasElement.PathName]));
-      end;
-  end;
+begin
+  Result := AClass.Create(AName, AParent);
+  Result.Visibility:=AVisibility;
+  if AClass.InheritsFrom(TPasModule) then
+    CurModule := TPasModule(Result);
+  // Track this element
+  If UpdateMode then
+    begin
+    DN:=FindDocNode(Result);    
+    If Assigned(DN) then
+      DN.IncRefCount;
+    end
+  else
+    DN:=Nil;  
+  // See if we need to write documentation for it
+  If MustWriteElement(Result,False) then
+    FNodeList.AddObject(Result.PathName,TNodePair.Create(Result,DN));
+end;
+
+Function TSkelEngine.WriteElement(Var F : Text;El : TPasElement; ADocNode : TDocNode) : Boolean;
 
   Function WriteOnlyShort(APasElement : TPasElement) : Boolean;
 
@@ -170,75 +217,61 @@ function TSkelEngine.CreateElement(AClass: TPTreeElement; const AName: String;
       Result:=(InheritsFrom(TPasType) and not InheritsFrom(TPasClassType)) or
               (InheritsFrom(TPasResString)) or
               (InheritsFrom(TPasVariable));
-
   end;
-
-Var
-  DN : TDocNode;
-
+  
+  Function NeedDeclaration(El : TPasElement) : boolean;
+  
+  begin
+    Result:=IsTypeVarConst(El) 
+            or WriteOnlyShort(El) 
+            or EL.InheritsFrom(TPasProcedure) 
+  end;
+    
 begin
-  Result := AClass.Create(AName, AParent);
+  // Check again, this time with full declaration.
+  Result:=MustWriteElement(El,True);
+  If Result and UpdateMode then
+     Result:=(ADocNode=Nil);
+  If Not Result Then
+    Exit;
   If UpdateMode then
+    Writeln(stderr,Format(ScreatingNewNode,[el.PathName]));
+  FEmittedList.Add(El.FullName); // So we don't emit again.
+  WriteLn(f);
+  if EmitClassSeparator and (El.ClassType = TPasClassType) then
     begin
-    DN:=FindDocNode(Result);    
-    If Assigned(DN) then
-      DN.IncRefCount;
-    end
-  else
-    DN:=Nil;  
-  Result.Visibility:=AVisibility;
-  if AClass.InheritsFrom(TPasModule) then
-    CurModule := TPasModule(Result);
-  if Result.ClassType = TPasModule then
-    begin
-    WriteLn(f);
     WriteLn(f, '<!--');
-    WriteLn(f, '  ====================================================================');
-    WriteLn(f, '    ', Result.Name);
-    WriteLn(f, '  ====================================================================');
+    WriteLn(f, '  ********************************************************************');
+    WriteLn(f, '    ', El.PathName);
+    WriteLn(f, '  ********************************************************************');
     WriteLn(f, '-->');
     WriteLn(f);
-    WriteLn(f, '<module name="', Result.Name, '">');
-    if not UpdateMode then
-      begin
-      WriteLn(f, '<short></short>');
-      WriteLn(f, '<descr>');
-      WriteLn(f, '</descr>');
-      end;
-    end
-  else if WriteThisNode(Result,DN) then
+    end;
+  If Not (WriteDeclaration and NeedDeclaration(El)) then  
+    Writeln(F,'<!-- ', El.ElementTypeName,' Visibility: ',VisibilityNames[El.Visibility], ' -->')
+  else  
     begin
-    EmittedList.Add(Result.FullName); // So we don't emit again.
-    WriteLn(f);
-    if EmitClassSeparator and (Result.ClassType = TPasClassType) then
+    Writeln(F,'<!-- ',El.ElementTypeName,' Visibility: ',VisibilityNames[El.Visibility]);
+    Writeln(F,'     Declaration: ',El.GetDeclaration(True),' -->');
+    end;
+  WriteLn(f,'<element name="', El.FullName, '">');
+  WriteLn(f, '<short></short>');
+  if Not WriteOnlyShort(El) then
+    begin
+    WriteLn(f, '<descr>');
+    WriteLn(f, '</descr>');
+    if not (DisableErrors or IsTypeVarConst(El)) then
       begin
-      WriteLn(f, '<!--');
-      WriteLn(f, '  ********************************************************************');
-      WriteLn(f, '    ', Result.PathName);
-      WriteLn(f, '  ********************************************************************');
-      WriteLn(f, '-->');
-      WriteLn(f);
+      WriteLn(f, '<errors>');
+      WriteLn(f, '</errors>');
       end;
-    Writeln(F,'<!-- ', Result.ElementTypeName,' Visibility: ',VisibilityNames[AVisibility], ' -->');
-    WriteLn(f,'<element name="', Result.FullName, '">');
-    WriteLn(f, '<short></short>');
-    if Not WriteOnlyShort(Result) then
+    if not DisableSeealso then
       begin
-      WriteLn(f, '<descr>');
-      WriteLn(f, '</descr>');
-      if not (DisableErrors or IsTypeVarConst(Result)) then
-        begin
-        WriteLn(f, '<errors>');
-        WriteLn(f, '</errors>');
-        end;
-      if not DisableSeealso then
-        begin
-        WriteLn(f, '<seealso>');
-        WriteLn(f, '</seealso>');
-        end;
+      WriteLn(f, '<seealso>');
+      WriteLn(f, '</seealso>');
       end;
-    WriteLn(f, '</element>');
     end;
+  WriteLn(f, '</element>');
 end;
 
 Procedure  TSkelEngine.DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
@@ -264,43 +297,147 @@ begin
   DoWriteUnReferencedNodes(RootDocNode,'');
 end;
 
+Procedure TSkelEngine.WriteNodes(Var F : Text; AModule : TPasModule; List : TStrings);
+
+Var
+  P : TNodePair;
+  I : integer;
+  
+begin
+  WriteLn(f);
+  WriteLn(f, '<!--');
+  WriteLn(f, '  ====================================================================');
+  WriteLn(f, '    ', Amodule.Name);
+  WriteLn(f, '  ====================================================================');
+  WriteLn(f, '-->');
+  WriteLn(f);
+  WriteLn(f, '<module name="', AModule.Name, '">');
+  if not UpdateMode then
+    begin
+    WriteLn(f, '<short></short>');
+    WriteLn(f, '<descr>');
+    WriteLn(f, '</descr>');
+    end;
+  Try 
+    For I:=0 to List.Count-1 do
+      begin
+      P:=List.Objects[i] as TNodePair;
+      If (P.Element<>AModule) then
+        WriteElement(F,P.Element,P.DocNode);
+      end;  
+  Finally
+    WriteLn(f, '');
+    WriteLn(f, '</module> <!-- ', AModule.Name, ' -->');
+    WriteLn(f, '');
+  end;   
+end;
+
+Procedure TSkelEngine.DocumentFile(Var F : Text; Const AFileName,ATarget,ACPU : String);
+
+Var
+  Module : TPasModule;
+  I : Integer;
+  N : TDocNode;
+     
+begin
+  FNodeList:=TStringList.Create;
+  Try
+    FEmittedList:=TStringList.Create;
+    FEmittedList.Sorted:=True;
+    try
+      Module:=ParseSource(Self,AFileName,ATarget,ACPU);
+      If UpdateMode then
+        begin
+        N:=FindDocNode(Module);
+        If Assigned(N) then
+           N.IncRefCount;
+         end;
+      If SortNodes then  
+        FNodelist.Sorted:=True;   
+      WriteNodes(F,Module,FNodeList);  
+      If UpdateMode then
+        WriteUnReferencedNodes;
+    Finally
+      FEmittedList.Free;
+    end;  
+  Finally  
+    For I:=0 to FNodeList.Count-1 do
+      FNodeList.Objects[i].Free;
+    FNodeList.Free;  
+  end;  
+end;
+
+{ ---------------------------------------------------------------------
+  Main program. Document all units.    
+  ---------------------------------------------------------------------}
+  
+Function DocumentPackage(Const APackageName,AOutputName : String; InputFiles,DescrFiles : TStrings) : String;
+
+Var
+  F : Text;
+  I,J : Integer;
+  Engine: TSkelEngine;
+
+begin
+  Assign(f, AOutputName);
+  Rewrite(f);
+  Try
+    WriteLn(f, '<?xml version="1.0" encoding="ISO-8859-1"?>');
+    WriteLn(f, '<fpdoc-descriptions>');
+    WriteLn(f, '<package name="', APackageName, '">');
+    Try
+      I:=0;
+      While (Result='') And (I<InputFiles.Count) do
+        begin
+        Engine := TSkelEngine.Create;
+        Try
+          Engine.SetPackageName(APackageName);
+          if UpdateMode then
+            For J:=0 to DescrFiles.Count-1 do
+              Engine.AddDocFile(DescrFiles[J]);
+          Try    
+            Engine.DocumentFile(F,InputFiles[I],OSTarget,CPUTarget);
+          except
+            on E:Exception do
+              Result:='Error while documenting: '+E.message;
+          end;
+        Finally
+          Engine.Free;
+        end;
+        Inc(I);
+        end;
+    Finally
+      WriteLn(f, '</package>');
+      WriteLn(f, '</fpdoc-descriptions>');
+    end;
+  finally
+    Close(f);
+  end;
+end;
+
+{ ---------------------------------------------------------------------
+    Option management
+  ---------------------------------------------------------------------}
+  
+
+var  
+  InputFiles, 
+  DescrFiles : TStringList;
+  DocLang : String;
+  PackageName, 
+  OutputName: String;
+
 procedure InitOptions;
 begin
   InputFiles := TStringList.Create;
   DescrFiles := TStringList.Create;
-  EmittedList:=TStringList.Create;
-  EmittedList.Sorted:=True;
 end;
 
 procedure FreeOptions;
+
 begin
   DescrFiles.Free;
   InputFiles.Free;
-  EmittedList.Free;
-end;
-
-Procedure Usage;
-
-begin
-  Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
-  Writeln('Where [options] is one or more of :');
-  Writeln(' --descr=filename    Filename for update.');
-  Writeln(' --disable-arguments Do not create nodes for function arguments.');
-  Writeln(' --disable-errors    Do not create errors node.');
-  Writeln(' --disable-function-results');
-  Writeln('                     Do not create nodes for function arguments.');
-  Writeln(' --disable-private   Do not create nodes for class private fields.');
-  Writeln(' --disable-protected Do not create nodes for class protected fields.');
-  Writeln(' --disable-seealso   Do not create seealso node.');
-  Writeln(' --emit-class-separator');
-  Writeln('                     Emit descriptive comment between classes.');
-  Writeln(' --help              Emit help.');
-  Writeln(' --input=cmdline     Input file to create skeleton for.');
-  Writeln('                     Use options are as for compiler.');
-  Writeln(' --lang=language     Use selected language.');
-  Writeln(' --output=filename   Send output to file.');
-  Writeln(' --package=name      Specify package name (mandatory).');
-  Writeln(' --update            Update mode. Output only missing nodes.');
 end;
 
 procedure ParseOption(const s: String);
@@ -342,6 +479,8 @@ begin
     DisableSeealso := True
   else if s = '--disable-private' then
     DisablePrivate := True
+  else if s = '--disable-override' then
+    DisableOverride := True
   else if s = '--disable-protected' then
     begin
     DisableProtected := True;
@@ -349,6 +488,10 @@ begin
     end
   else if (s = '--emitclassseparator') or (s='--emit-class-separator') then
     EmitClassSeparator := True
+  else if (s = '--emit-declaration') then
+    WriteDeclaration := True
+  else if (s = '--sort-nodes') then
+    SortNodes := True
   else
   begin
     i := Pos('=', s);
@@ -379,7 +522,7 @@ begin
   end;
 end;
 
-procedure ParseCommandLine;
+Function ParseCommandLine : Integer;
 
 Const
 {$IFDEF Unix}
@@ -391,7 +534,9 @@ Const
 var
   MOFilename: string;
   i: Integer;
+  
 begin
+  Result:=0;
   DocLang:='';
   for i := 1 to ParamCount do
     ParseOption(ParamStr(i));
@@ -405,95 +550,82 @@ begin
     // Translate internal documentation strings
     TranslateDocStrings(DocLang);
     end;
+  // Action is to create the XML skeleton
+  if Length(PackageName) = 0 then
+    begin
+    WriteLn(SNoPackageNameProvided);
+    Result:=2;
+    end;
+  if DescrFiles.IndexOf(OutputName)<>-1 then
+    begin
+    Writeln(SOutputMustNotBeDescr);
+    Result:=3;
+    end;
 end;
 
+{ ---------------------------------------------------------------------
+  Usage  
+  ---------------------------------------------------------------------}
+  
+Procedure Usage;
 
+begin
+  Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
+  Writeln('Where [options] is one or more of :');
+  Writeln(' --descr=filename    Filename for update.');
+  Writeln(' --disable-arguments Do not create nodes for function arguments.');
+  Writeln(' --disable-errors    Do not create errors node.');
+  Writeln(' --disable-function-results');
+  Writeln('                     Do not create nodes for function arguments.');
+  Writeln(' --disable-override  Do not create nodes for override methods.');
+  Writeln(' --disable-private   Do not create nodes for class private fields.');
+  Writeln(' --disable-protected Do not create nodes for class protected fields.');
+  Writeln(' --disable-seealso   Do not create seealso node.');
+  Writeln(' --emit-class-separator');
+  Writeln('                     Emit descriptive comment between classes.');
+  Writeln(' --emit-declaration  Emit declaration for elements.');
+  Writeln(' --help              Emit help.');
+  Writeln(' --input=cmdline     Input file to create skeleton for.');
+  Writeln('                     Use options are as for compiler.');
+  Writeln(' --lang=language     Use selected language.');
+  Writeln(' --output=filename   Send output to file.');
+  Writeln(' --package=name      Specify package name (mandatory).');
+  Writeln(' --sort-nodes        Sort element nodes (not modules)');
+  Writeln(' --update            Update mode. Output only missing nodes.');
+end;
 
+{ ---------------------------------------------------------------------
+  Main Program  
+  ---------------------------------------------------------------------}
+  
+Procedure Run;
+  
 var
-  i,j: Integer;
-  Module: TPasModule;
-  N : TDocNode;
+  E: Integer;
 
 begin
-  InitOptions;
-  ParseCommandLine;
   WriteLn(STitle);
   WriteLn(Format(SVersion, [FPCVersion, FPCDate]));
   WriteLn(SCopyright);
-  WriteLn;
-  if CmdLineAction = actionHelp then
-    Usage
-  else
-    begin
-    // Action is to create the XML skeleton
-
-    if Length(PackageName) = 0 then
-      begin
-      WriteLn(SNoPackageNameProvided);
-      Halt(2);
-      end;
-
-    if DescrFiles.IndexOf(OutputName)<>-1 then
+  InitOptions;
+  Try
+    E:=ParseCommandLine;
+    If E<>0 then
+      Halt(E);
+    WriteLn;
+    if CmdLineAction = actionHelp then
+      Usage
+    else
       begin
-      Writeln(SOutputMustNotBeDescr);
-      Halt(3)
+      DocumentPackage(PackageName,OutputName,InputFiles,DescrFiles);
+      WriteLn(SDone);
       end;
+  Finally  
+    FreeOptions;
+  end;  
+end;
 
-    Assign(f, OutputName);
-    Rewrite(f);
-
-    WriteLn(f, '<?xml version="1.0" encoding="ISO-8859-1"?>');
-    WriteLn(f, '<fpdoc-descriptions>');
-    WriteLn(f, '<package name="', PackageName, '">');
-
-    // Process all source files
-    for i := 0 to InputFiles.Count - 1 do
-    begin
-      Engine := TSkelEngine.Create;
-      try
-       try
-         Engine.SetPackageName(PackageName);
-         if UpdateMode then
-           For J:=0 to DescrFiles.Count-1 do
-             Engine.AddDocFile(DescrFiles[J]);
-         Module := ParseSource(Engine, InputFiles[i], OSTarget, CPUTarget);
-         If UpdateMode then
-           begin
-           N:=Engine.FindDocNode(Module);
-           If Assigned(N) then
-             N.IncRefCount;
-           end;
-         WriteLn(f, '');
-         WriteLn(f, '</module> <!-- ', Module.Name, ' -->');
-         WriteLn(f, '');
-       except
-         on e:EFileNotFoundError do
-           begin
-             Writeln(StdErr,' file ', e.message, ' not found');
-             close(f);
-             Halt(1);
-           end;
-         on e:EParserError do
-           begin
-             Writeln(StdErr,'', e.filename,'(',e.row,',',e.column,') Fatal: ',e.message);
-             close(f);
-             Halt(1);
-           end;
-       end;
-        If UpdateMode then
-          Engine.WriteUnReferencedNodes;
-      finally
-        Engine.Free;
-       end;
-    end;
-
-    WriteLn(f, '</package>');
-    WriteLn(f, '</fpdoc-descriptions>');
-
-    Close(f);
-    WriteLn(SDone);
-    end;
-
-  FreeOptions;
-
+Begin
+  Run;  
 end.
+