mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 04:22:21 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1211 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1211 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
 | 
						|
    FPDoc  -  Free Pascal Documentation Tool
 | 
						|
    Copyright (C) 2000 - 2003 by
 | 
						|
      Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
 | 
						|
 | 
						|
    * Skeleton XML description file generator
 | 
						|
 | 
						|
    See the file COPYING, included in this distribution,
 | 
						|
    for details about the license.
 | 
						|
 | 
						|
    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.
 | 
						|
}
 | 
						|
 | 
						|
(* --- Version 1.0 ---
 | 
						|
uMakeSkel merges the FPDoc and MakeSkel functionality, for use in applications.
 | 
						|
 | 
						|
The TFPDocMaker class supports the following functionality:
 | 
						|
- Project generation from a commandline, lpk or lpi file.
 | 
						|
- FPDoc documentation generation, optionally syntax check only.
 | 
						|
- MakeSkel skeleton generation or update.
 | 
						|
- Processing of single units or entire packages.
 | 
						|
- Added and extended commandline options.
 | 
						|
 | 
						|
Everything else is done in a separate documentation manager.
 | 
						|
The documentation manager maintains its own projects
 | 
						|
and creates temporary TFPDocProjects and TFPDocPackages on demand.
 | 
						|
*)
 | 
						|
 | 
						|
unit umakeskel;
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
{$mode objfpc}
 | 
						|
{$h+}
 | 
						|
 | 
						|
{$IF FPC_FULLVERSION<20701}
 | 
						|
  {$ERROR requires FPC 2.7.1 at least}
 | 
						|
{$ENDIF}
 | 
						|
 | 
						|
uses
 | 
						|
  SysUtils, Classes, Gettext,
 | 
						|
  dGlobals, PasTree, PParser,PScanner,
 | 
						|
  ConfigFile,
 | 
						|
  mkfpdoc, fpdocproj;
 | 
						|
 | 
						|
resourcestring
 | 
						|
  STitle = 'MakeSkel - FPDoc skeleton XML description file generator';
 | 
						|
  SVersion = 'Version %s [%s]';
 | 
						|
  SCopyright = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org';
 | 
						|
  SCmdLineHelp = 'See documentation for usage.';
 | 
						|
  SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
 | 
						|
  SNoPackageNameProvided = 'Please specify a package name with --package=<name>';
 | 
						|
  SOutputMustNotBeDescr = 'Output file must be different from description filenames.';
 | 
						|
  SCreatingNewNode = 'Creating documentation for new node : %s';
 | 
						|
  SNodeNotReferenced = 'Documentation node "%s" no longer used';
 | 
						|
  SDone = 'Done.';
 | 
						|
//from fpdocxmlopts
 | 
						|
  SErrInvalidRootNode = 'Invalid options root node: Got "%s", expected "docproject"';
 | 
						|
  SErrNoPackagesNode = 'No "packages" node found in docproject';
 | 
						|
 | 
						|
type
 | 
						|
  TCmdLineAction = (actionHelp, actionConvert);
 | 
						|
 | 
						|
(* EngineOptions plus MakeSkel options.
 | 
						|
  Used in the commandline parsers, passed to the Engine.
 | 
						|
  Project.Options are ignored by TFDocMaker.(?)
 | 
						|
*)
 | 
						|
 | 
						|
  { TCmdOptions }
 | 
						|
 | 
						|
  TCmdOptions = class(TEngineOptions)
 | 
						|
  public
 | 
						|
    WriteDeclaration,
 | 
						|
    UpdateMode,
 | 
						|
    SortNodes,
 | 
						|
    DisableOverride,
 | 
						|
    DisableErrors,
 | 
						|
    DisableSeealso,
 | 
						|
    DisableArguments,
 | 
						|
    DisableProtected,
 | 
						|
    DisablePrivate,
 | 
						|
    DisableFunctionResults: Boolean;
 | 
						|
    EmitClassSeparator: Boolean;
 | 
						|
    Verbose,
 | 
						|
    Modified: boolean;
 | 
						|
    procedure Assign(Source: TPersistent); override;
 | 
						|
    procedure LoadConfig(cf: TConfigFile; AProfile: string);
 | 
						|
    procedure SaveConfig(cf: TConfigFile; AProfile: string);
 | 
						|
    procedure BackendToPairs(Dest: TStrings);
 | 
						|
    procedure BackendFromPairs(Source: TStrings);
 | 
						|
  end;
 | 
						|
 | 
						|
  { TSkelEngine }
 | 
						|
 | 
						|
  TSkelEngine = class(TFPDocEngine)
 | 
						|
  Private
 | 
						|
    FEmittedList, 
 | 
						|
    FNodeList,
 | 
						|
    FModules : TStringList;
 | 
						|
    FOptions: TCmdOptions;
 | 
						|
    Procedure  DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
 | 
						|
    procedure SetOptions(AValue: TCmdOptions);
 | 
						|
  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;
 | 
						|
    property Options: TCmdOptions read FOptions write SetOptions;
 | 
						|
  end;
 | 
						|
 | 
						|
  THandleOption = function(const Cmd, Arg: string): boolean;
 | 
						|
 | 
						|
  TCreatorAction = (
 | 
						|
    caDefault,
 | 
						|
    caDryRun,
 | 
						|
    caUsage, //explicit or on all errors?
 | 
						|
    caInvalid,
 | 
						|
    caWriteProject
 | 
						|
  );
 | 
						|
 | 
						|
  { TFPDocMaker }
 | 
						|
(* MakeSkel functionality as a class.
 | 
						|
*)
 | 
						|
  TFPDocMaker = class(TFPDocCreator)
 | 
						|
  private
 | 
						|
    FDescrDir: string;
 | 
						|
    FInputDir: string;
 | 
						|
    FOnOption: THandleOption;
 | 
						|
    FOptions: TCmdOptions;
 | 
						|
    function GetDescrDir: string;
 | 
						|
    function GetInputDir: string;
 | 
						|
    procedure SetDescrDir(AValue: string);
 | 
						|
    procedure SetInputDir(AValue: string);
 | 
						|
    procedure SetOnOption(AValue: THandleOption);
 | 
						|
    procedure SetOptions(AValue: TCmdOptions);
 | 
						|
  protected
 | 
						|
    FCmdAction: TCreatorAction;
 | 
						|
    FDryRun: boolean;
 | 
						|
    FPackage: TFPDocPackage;
 | 
						|
    FProjectFile: boolean;
 | 
						|
    FWriteProjectFile: string;
 | 
						|
    FTranslated: string;
 | 
						|
    procedure SetCmdAction(AValue: TCreatorAction);
 | 
						|
    procedure SetDryRun(AValue: boolean);
 | 
						|
    procedure SetPackage(AValue: TFPDocPackage);
 | 
						|
    procedure SetWriteProjectFile(AValue: string);
 | 
						|
    function  ParseCommon(var Cmd, Arg: string): TCreatorAction;
 | 
						|
  public
 | 
						|
    Function  DocumentPackage(Const APackageName,AOutputName: string; InputFiles, DescrFiles : TStrings) : String;
 | 
						|
    procedure CreateUnitDocumentation(const AUnit: string; ParseOnly: Boolean);
 | 
						|
  public
 | 
						|
    constructor Create(AOwner: TComponent); override;
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure AddDirToFileList(List: TStrings; const ADirName, AMask: String);
 | 
						|
    procedure AddToFileList(List: TStrings; const FileName: String);
 | 
						|
    function  UnitSpec(AUnit: string): string;
 | 
						|
    function  ImportName(AIndex: integer): string;
 | 
						|
    procedure LogToStdOut(Sender: TObject; const msg: string);
 | 
						|
    procedure LogToStdErr(Sender: TObject; const msg: string);
 | 
						|
  //parsing
 | 
						|
    function  ParseFPDocOption(const S: string):  TCreatorAction;
 | 
						|
    function  ParseUpdateOption(const S: string):  TCreatorAction;
 | 
						|
    function  CheckSkelOptions: string;
 | 
						|
    function  CleanXML(const FileName: string): boolean;
 | 
						|
    function  SelectedPackage: TFPDocPackage;
 | 
						|
    //property Package: TFPDocPackage read SelectedPackage write SetPackage;
 | 
						|
    property Package: TFPDocPackage read FPackage write SetPackage; //without message
 | 
						|
    property CmdAction: TCreatorAction read FCmdAction write SetCmdAction;
 | 
						|
    property DryRun: boolean read FDryRun write SetDryRun;
 | 
						|
    property ReadProject: boolean read FProjectFile;
 | 
						|
    property WriteProjectFile: string read FWriteProjectFile write SetWriteProjectFile;
 | 
						|
    property OnOption: THandleOption read FOnOption write SetOnOption;
 | 
						|
    property InputDir: string read GetInputDir write SetInputDir;
 | 
						|
    property DescrDir: string read GetDescrDir write SetDescrDir;
 | 
						|
    property CmdOptions: TCmdOptions read FOptions write SetOptions;
 | 
						|
  end;
 | 
						|
 | 
						|
//Extract next commandline option from a string
 | 
						|
Function GetNextWord(Var s : string) : String;
 | 
						|
 | 
						|
//Get package name from Imports spec
 | 
						|
function ExtractImportName(const s: string): string;
 | 
						|
//Get Unit filename from Inputs or Descriptions
 | 
						|
function UnitFile(AList: TStrings; AIndex: integer): string;
 | 
						|
//Get Unit name from Inputs or Descriptions
 | 
						|
function ExtractUnitName(AList: TStrings; AIndex: integer): string;
 | 
						|
function ExtractUnitName(s: string): string;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
uses
 | 
						|
  dom,
 | 
						|
  dWriter;
 | 
						|
 | 
						|
(* Extract (remove!) next commandline option from a string.
 | 
						|
  Handle quoted arguments, but do not unquote.
 | 
						|
  Option may be partially quoted, e.g. -opt="arg with blanks"
 | 
						|
*)
 | 
						|
Function GetNextWord(Var s : string) : String;
 | 
						|
Const
 | 
						|
  WhiteSpace = [' ',#9,#10,#13];
 | 
						|
var
 | 
						|
  i,j: integer;
 | 
						|
  quoted: boolean;
 | 
						|
begin
 | 
						|
  I:=1;
 | 
						|
  quoted := False;
 | 
						|
  While (I<=Length(S)) and (S[i] in WhiteSpace) do
 | 
						|
    Inc(I);
 | 
						|
  J:=I;
 | 
						|
{
 | 
						|
    While (J<=Length(S)) and (not (S[J] in WhiteSpace)) do
 | 
						|
      Inc(J);
 | 
						|
}
 | 
						|
  While (J<=Length(S)) do begin
 | 
						|
    if (s[j] = '"') then begin
 | 
						|
      if quoted then
 | 
						|
        break;
 | 
						|
      quoted := True;
 | 
						|
    end else if not quoted and (S[J] in WhiteSpace) then
 | 
						|
      break;
 | 
						|
    Inc(J);
 | 
						|
  end;
 | 
						|
  if (I<=Length(S)) then
 | 
						|
    Result:=Copy(S,I,J-I);
 | 
						|
  Delete(S,1,J);
 | 
						|
end;
 | 
						|
 | 
						|
function ExtractImportName(const s: string): string;
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  Result := s;
 | 
						|
  i := Pos(',', Result);
 | 
						|
  if i > 1 then
 | 
						|
    SetLength(Result, i-1);
 | 
						|
  Result := ChangeFileExt(ExtractFileName(Result), '');
 | 
						|
end;
 | 
						|
 | 
						|
function ExtractUnitName(s: string): string;
 | 
						|
begin
 | 
						|
  Result := ChangeFileExt(ExtractFileName(s), '');
 | 
						|
end;
 | 
						|
 | 
						|
(* Unit name from Inputs[i] or Descriptions[i]
 | 
						|
  Package name from Imports?
 | 
						|
*)
 | 
						|
function ExtractUnitName(AList: TStrings; AIndex: integer): string;
 | 
						|
begin
 | 
						|
  Result := UnitFile(AList, AIndex);
 | 
						|
  if Result <> '' then
 | 
						|
    Result := ChangeFileExt(ExtractFileName(Result), '');
 | 
						|
end;
 | 
						|
 | 
						|
(* Extract a file reference from Inputs or Descriptions list.
 | 
						|
  Check for existing list and item.
 | 
						|
*)
 | 
						|
function UnitFile(AList: TStrings; AIndex: integer): string;
 | 
						|
var
 | 
						|
  s: string;
 | 
						|
begin
 | 
						|
  if assigned(AList) and (AIndex < AList.Count) then begin
 | 
						|
    s := AList[AIndex];
 | 
						|
    while s <> '' do begin
 | 
						|
      Result := GetNextWord(s);
 | 
						|
      if (Result <> '') and (Result[1] <> '-') then
 | 
						|
        exit; //found a non-option
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Result := ''; //should never happen!
 | 
						|
end;
 | 
						|
 | 
						|
type
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
{ TCmdOptions }
 | 
						|
 | 
						|
procedure TCmdOptions.Assign(Source: TPersistent);
 | 
						|
var
 | 
						|
  s: TCmdOptions absolute Source;
 | 
						|
begin
 | 
						|
  inherited Assign(Source); //writes to the local copy!
 | 
						|
  if Source is TCmdOptions then begin
 | 
						|
    WriteDeclaration := s.WriteDeclaration;
 | 
						|
    DisableOverride := s.DisableOverride;
 | 
						|
    DisableErrors:=s.DisableErrors;
 | 
						|
    DisableSeealso:=s.DisableSeealso;
 | 
						|
    DisableArguments:=s.DisableArguments;
 | 
						|
    DisableFunctionResults := s.DisableFunctionResults;
 | 
						|
    ShowPrivate := s.ShowPrivate;
 | 
						|
    DisableProtected:=s.DisableProtected;
 | 
						|
    SortNodes := s.SortNodes;
 | 
						|
    Verbose:=s.Verbose;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
const SecOpts = 'default';
 | 
						|
 | 
						|
procedure TCmdOptions.LoadConfig(cf: TConfigFile; AProfile: string);
 | 
						|
var
 | 
						|
  s, sec: string;
 | 
						|
begin
 | 
						|
//MakeSkel
 | 
						|
  WriteDeclaration := cf.ReadBool(SecOpts, 'WriteDeclaration', True);
 | 
						|
  DisableOverride := cf.ReadBool(SecOpts, 'DisableOverride', False);
 | 
						|
  DisableErrors := cf.ReadBool(SecOpts, 'DisableErrors', False);
 | 
						|
  DisableSeealso := cf.ReadBool(SecOpts, 'DisableSeealso', False);
 | 
						|
  DisableArguments := cf.ReadBool(SecOpts, 'DisableArguments', False);
 | 
						|
  DisableFunctionResults := cf.ReadBool(SecOpts, 'DisableFunctionResults', False);
 | 
						|
  ShowPrivate := cf.ReadBool(SecOpts, 'ShowPrivate', True);
 | 
						|
  DisableProtected := cf.ReadBool(SecOpts, 'DisableProtected', False);
 | 
						|
  SortNodes := cf.ReadBool(SecOpts, 'SortNodes', False);
 | 
						|
//Engine
 | 
						|
  StopOnParseError :=  cf.ReadBool(SecOpts, 'StopOnParseError', False);
 | 
						|
  WarnNoNode :=  cf.ReadBool(SecOpts, 'WarnNoNode', True);
 | 
						|
  InterfaceOnly :=  cf.ReadBool(SecOpts, 'InterfaceOnly', True);
 | 
						|
  if AProfile = '' then
 | 
						|
    AProfile := SecOpts;
 | 
						|
  OSTarget := cf.ReadString(AProfile, 'OSTarget', DefOSTarget);
 | 
						|
  CPUTarget := cf.ReadString(AProfile, 'CPUTarget', DefCPUTarget);
 | 
						|
  Language := cf.ReadString(AProfile, 'Language', '');
 | 
						|
  Backend :=  cf.ReadString(AProfile, 'Backend', 'html');
 | 
						|
  MoDir :=  cf.ReadString(AProfile, 'MoDir', '');
 | 
						|
  HideProtected :=  cf.ReadBool(AProfile, 'HideProtected', False);
 | 
						|
  ShowPrivate :=  cf.ReadBool(AProfile, 'ShowPrivate', False);
 | 
						|
  DontTrim := cf.ReadBool(AProfile, 'DontTrim', False);
 | 
						|
//Backend
 | 
						|
  s := cf.ReadString(AProfile, 'BackendOptions', '');
 | 
						|
  BackendOptions.CommaText := s;
 | 
						|
//finally
 | 
						|
  Modified := False;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCmdOptions.SaveConfig(cf: TConfigFile; AProfile: string);
 | 
						|
begin
 | 
						|
//MakeSkel
 | 
						|
  cf.WriteBool(SecOpts, 'WriteDeclaration', WriteDeclaration);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableOverride', DisableOverride);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableErrors', DisableErrors);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableSeealso', DisableSeealso);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableArguments', DisableArguments);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableFunctionResults', DisableFunctionResults);
 | 
						|
  cf.WriteBool(SecOpts, 'DisablePrivate', DisablePrivate);
 | 
						|
  cf.WriteBool(SecOpts, 'DisableProtected', DisableProtected);
 | 
						|
  cf.WriteBool(SecOpts, 'SortNodes', SortNodes);
 | 
						|
//Engine
 | 
						|
  cf.WriteBool(SecOpts, 'StopOnParseError', StopOnParseError);
 | 
						|
  cf.WriteBool(SecOpts, 'WarnNoNode', WarnNoNode);
 | 
						|
  cf.WriteBool(SecOpts, 'DontTrim', DontTrim);
 | 
						|
  if AProfile = '' then
 | 
						|
    AProfile := SecOpts;
 | 
						|
  cf.WriteString(AProfile, 'OSTarget', OSTarget);
 | 
						|
  cf.WriteString(AProfile, 'CPUTarget', CPUTarget);
 | 
						|
  cf.WriteString(AProfile, 'Language', Language);
 | 
						|
  cf.WriteString(AProfile, 'Backend', Backend);
 | 
						|
  cf.WriteString(AProfile, 'MoDir', MoDir);
 | 
						|
  cf.WriteBool(AProfile, 'HideProtected', HideProtected);
 | 
						|
  cf.WriteBool(AProfile, 'ShowPrivate', ShowPrivate);
 | 
						|
  cf.WriteBool(AProfile, 'InterfaceOnly', InterfaceOnly);
 | 
						|
//Backend
 | 
						|
  if BackendOptions.Count > 0 then
 | 
						|
    cf.WriteString(AProfile, 'BackendOptions', BackendOptions.CommaText);
 | 
						|
//finally
 | 
						|
  Modified := False;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCmdOptions.BackendToPairs(Dest: TStrings);
 | 
						|
var
 | 
						|
  i, n: integer;
 | 
						|
begin
 | 
						|
  Dest.Clear;
 | 
						|
  n := BackendOptions.Count div 2;
 | 
						|
  if n = 0 then
 | 
						|
    exit;
 | 
						|
  Dest.Capacity := n;
 | 
						|
  for i := 0 to n-1 do begin
 | 
						|
    Dest.Add(BackendOptions[i*2] + '=' + BackendOptions[i*2 + 1]);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TCmdOptions.BackendFromPairs(Source: TStrings);
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  BackendOptions.Clear;
 | 
						|
  BackendOptions.Capacity:=Source.Count * 2;
 | 
						|
  for i := 0 to Source.Count - 1 do begin
 | 
						|
    BackendOptions.Add(Source.Names[i]);
 | 
						|
    BackendOptions.Add(Source.ValueFromIndex[i]);
 | 
						|
  end;
 | 
						|
  Modified := True; //todo: only if really changed?
 | 
						|
end;
 | 
						|
 | 
						|
Constructor TNodePair.Create(AnElement : TPasElement; ADocNode : TDocNode);
 | 
						|
 | 
						|
begin
 | 
						|
  Fel:=Anelement;
 | 
						|
  FNode:=ADocNode;
 | 
						|
end;
 | 
						|
 | 
						|
function TSkelEngine.FindModule(const AName: String): TPasModule; 
 | 
						|
 | 
						|
Var
 | 
						|
  I : Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=Inherited FindModule(AName);
 | 
						|
  If (Result=Nil) then
 | 
						|
    begin // Create dummy list and search in that.
 | 
						|
    If (FModules=Nil) then
 | 
						|
      begin
 | 
						|
      FModules:=TStringList.Create;
 | 
						|
      FModules.Sorted:=True;
 | 
						|
      FModules.OwnsObjects := True; //auto destroy
 | 
						|
      end;
 | 
						|
    I:=FModules.IndexOf(AName);
 | 
						|
    IF (I=-1) then
 | 
						|
      begin
 | 
						|
      Result:=TPasModule.Create(AName,Nil);
 | 
						|
      FModules.AddObject(AName,Result);
 | 
						|
      end
 | 
						|
    else
 | 
						|
      Result:=FModules.Objects[i] as TPasModule;  
 | 
						|
    end;  
 | 
						|
end;
 | 
						|
 | 
						|
Destructor TSkelEngine.Destroy; 
 | 
						|
Var
 | 
						|
  I : Integer;
 | 
						|
begin
 | 
						|
{$IFDEF old}
 | 
						|
  If Assigned(FModules) then
 | 
						|
    begin
 | 
						|
    For I:=0 to FModules.Count-1 do
 | 
						|
      FModules.Objects[i].Free;
 | 
						|
    FreeAndNil(FModules);    
 | 
						|
    end;
 | 
						|
{$ELSE}
 | 
						|
  FreeAndNil(FModules);
 | 
						|
{$ENDIF}
 | 
						|
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 Options.DisablePrivate or (PT.Visibility<>visPrivate)) and
 | 
						|
                       (not Options.DisableProtected or (PT.Visibility<>visProtected)));
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  Result:=Assigned(El.Parent) and (Length(El.Name) > 0) and
 | 
						|
          (ParentVisible and (not Options.DisableArguments or (El.ClassType <> TPasArgument))) and
 | 
						|
          (ParentVisible and (not Options.DisableFunctionResults or (El.ClassType <> TPasResultElement))) and
 | 
						|
          (not Options.DisablePrivate or (el.Visibility<>visPrivate)) and
 | 
						|
          (not Options.DisableProtected or (el.Visibility<>visProtected));
 | 
						|
  If Result and Full then
 | 
						|
    begin
 | 
						|
    Result:=(Not Assigned(FEmittedList) or (FEmittedList.IndexOf(El.FullName)=-1));
 | 
						|
    If Options.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;
 | 
						|
 | 
						|
Var
 | 
						|
  DN : TDocNode;
 | 
						|
 | 
						|
begin
 | 
						|
  Result := AClass.Create(AName, AParent);
 | 
						|
  Result.Visibility:=AVisibility;
 | 
						|
  if AClass.InheritsFrom(TPasModule) then
 | 
						|
    CurModule := TPasModule(Result);
 | 
						|
  // Track this element
 | 
						|
  If Options.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;
 | 
						|
 | 
						|
  begin
 | 
						|
    Result:=(APasElement.ClassType=TPasArgument) or
 | 
						|
            (APasElement.ClassType=TPasResultElement) or
 | 
						|
            (APasElement.ClassType=TPasEnumValue);
 | 
						|
  end;
 | 
						|
 | 
						|
  Function IsTypeVarConst(APasElement : TPasElement) : Boolean;
 | 
						|
 | 
						|
  begin
 | 
						|
    With APasElement do
 | 
						|
      Result:=(InheritsFrom(TPasType) and not InheritsFrom(TPasClassType)) or
 | 
						|
              (InheritsFrom(TPasResString)) or
 | 
						|
              (InheritsFrom(TPasVariable));
 | 
						|
  end;
 | 
						|
  
 | 
						|
  Function NeedDeclaration(El : TPasElement) : boolean;
 | 
						|
  
 | 
						|
  begin
 | 
						|
    Result:=IsTypeVarConst(El) 
 | 
						|
            or WriteOnlyShort(El) 
 | 
						|
            or EL.InheritsFrom(TPasProcedure) 
 | 
						|
  end;
 | 
						|
    
 | 
						|
begin
 | 
						|
  // Check again, this time with full declaration.
 | 
						|
  Result:=MustWriteElement(El,True);
 | 
						|
  If Result and Options.UpdateMode then
 | 
						|
     Result:=(ADocNode=Nil);
 | 
						|
  If Not Result Then
 | 
						|
    Exit;
 | 
						|
  If Options.UpdateMode then
 | 
						|
    DoLog(Format(ScreatingNewNode,[el.PathName]));
 | 
						|
  FEmittedList.Add(El.FullName); // So we don't emit again.
 | 
						|
  WriteLn(f);
 | 
						|
  if Options.EmitClassSeparator and (El.ClassType = TPasClassType) then
 | 
						|
    begin
 | 
						|
    WriteLn(f, '<!--');
 | 
						|
    WriteLn(f, '  ********************************************************************');
 | 
						|
    WriteLn(f, '    ', El.PathName);
 | 
						|
    WriteLn(f, '  ********************************************************************');
 | 
						|
    WriteLn(f, '-->');
 | 
						|
    WriteLn(f);
 | 
						|
    end;
 | 
						|
  If Not (Options.WriteDeclaration and NeedDeclaration(El)) then
 | 
						|
    Writeln(F,'<!-- ', El.ElementTypeName,' Visibility: ',VisibilityNames[El.Visibility], ' -->')
 | 
						|
  else  
 | 
						|
    begin
 | 
						|
    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 (Options.DisableErrors or IsTypeVarConst(El)) then
 | 
						|
      begin
 | 
						|
      WriteLn(f, '<errors>');
 | 
						|
      WriteLn(f, '</errors>');
 | 
						|
      end;
 | 
						|
    if not Options.DisableSeealso then
 | 
						|
      begin
 | 
						|
      WriteLn(f, '<seealso>');
 | 
						|
      WriteLn(f, '</seealso>');
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  WriteLn(f, '</element>');
 | 
						|
end;
 | 
						|
 | 
						|
Procedure  TSkelEngine.DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
 | 
						|
 | 
						|
begin
 | 
						|
  If (N<>Nil) then
 | 
						|
    begin
 | 
						|
    If (NodePath<>'') then
 | 
						|
      NodePath:=NodePath+'.';
 | 
						|
    DoWriteUnReferencedNodes(N.FirstChild,NodePath+N.Name);
 | 
						|
    While (N<>Nil) do
 | 
						|
      begin
 | 
						|
      if (N.RefCount=0) and (N.Node<>Nil) and (Not N.TopicNode) then
 | 
						|
        DoLog(Format(SNodeNotReferenced,[NodePath+N.Name]));
 | 
						|
      N:=N.NextSibling;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TSkelEngine.SetOptions(AValue: TCmdOptions);
 | 
						|
begin
 | 
						|
  if FOptions=AValue then Exit;
 | 
						|
  FOptions:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TSkelEngine.WriteUnReferencedNodes;
 | 
						|
 | 
						|
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 Options.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, True); //use streams
 | 
						|
      If Options.UpdateMode then
 | 
						|
        begin
 | 
						|
        N:=FindDocNode(Module);
 | 
						|
        If Assigned(N) then
 | 
						|
           N.IncRefCount;
 | 
						|
         end;
 | 
						|
      If Options.SortNodes then
 | 
						|
        FNodelist.Sorted:=True;   
 | 
						|
      WriteNodes(F,Module,FNodeList);  
 | 
						|
      If Options.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.    
 | 
						|
  ---------------------------------------------------------------------}
 | 
						|
 | 
						|
{ TFPDocMaker }
 | 
						|
 | 
						|
constructor TFPDocMaker.Create(AOwner: TComponent);
 | 
						|
begin
 | 
						|
  inherited Create(AOwner);
 | 
						|
  FOptions := TCmdOptions.Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TFPDocMaker.Destroy;
 | 
						|
begin
 | 
						|
  FreeAndNil(FOptions);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.SelectedPackage: TFPDocPackage;
 | 
						|
begin
 | 
						|
  Result:=FPackage;
 | 
						|
  if (FPackage=Nil) or (FPackage.Name='') then
 | 
						|
    begin
 | 
						|
    DoLog(SNeedPackageName);
 | 
						|
    //Usage(1); - in application
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetOnOption(AValue: THandleOption);
 | 
						|
begin
 | 
						|
  if FOnOption=AValue then Exit;
 | 
						|
  FOnOption:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetDescrDir(AValue: string);
 | 
						|
begin
 | 
						|
  if FDescrDir=AValue then Exit;
 | 
						|
  FDescrDir:=AValue;
 | 
						|
  AddDirToFileList(SelectedPackage.Descriptions, AValue, '*.xml');
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.GetDescrDir: string;
 | 
						|
begin
 | 
						|
  if FDescrDir = '' then begin
 | 
						|
    if SelectedPackage.Descriptions.Count > 0 then begin
 | 
						|
      Result := FPackage.Descriptions[0];
 | 
						|
      FDescrDir := ExtractFilePath(Result); //include separator
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Result := FDescrDir;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.UnitSpec(AUnit: string): string;
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
  w: string;
 | 
						|
begin
 | 
						|
  for i := 0 to SelectedPackage.Inputs.Count - 1 do begin
 | 
						|
    w := ExtractUnitName(FPackage.Inputs, i);
 | 
						|
    if CompareText(w, AUnit) = 0 then begin
 | 
						|
      Result := FPackage.Inputs[i];
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Result := '';
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.ImportName(AIndex: integer): string;
 | 
						|
begin
 | 
						|
  Result := ExtractImportName(SelectedPackage.Imports[AIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.GetInputDir: string;
 | 
						|
var
 | 
						|
  W: string;
 | 
						|
begin
 | 
						|
  if (FInputDir = '') and (SelectedPackage.Inputs.Count > 0) then begin
 | 
						|
    Result := FPackage.Inputs[0];
 | 
						|
    while Result <> '' do begin
 | 
						|
      w := GetNextWord(Result);
 | 
						|
      if (w <> '') and (w[1] <> '-') then begin
 | 
						|
        FInputDir := ExtractFilePath(W); //include separator
 | 
						|
        break;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
  Result := FInputDir;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetInputDir(AValue: string);
 | 
						|
begin
 | 
						|
  if FInputDir=AValue then Exit;
 | 
						|
  FInputDir:=AValue;
 | 
						|
  AddDirToFileList(SelectedPackage.Inputs, AValue, '*.pp');
 | 
						|
  AddDirToFileList(SelectedPackage.Inputs, AValue, '*.pas');
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetOptions(AValue: TCmdOptions);
 | 
						|
begin
 | 
						|
  //if FOptions=AValue then Exit;
 | 
						|
  FOptions.Assign(AValue);  //the local MakeSkel options
 | 
						|
  Options.Assign(AValue);   //the FPDoc Engine options
 | 
						|
  Verbose := AValue.Verbose; //not in Options
 | 
						|
end;
 | 
						|
 | 
						|
(* Check the options, return errors as message strings.
 | 
						|
*)
 | 
						|
function TFPDocMaker.CheckSkelOptions: string;
 | 
						|
 | 
						|
Const
 | 
						|
{$IFDEF Unix}
 | 
						|
  MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
 | 
						|
{$ELSE}
 | 
						|
  MoFileTemplate ='intl/makeskel.%s.mo';
 | 
						|
{$ENDIF}
 | 
						|
 | 
						|
Var
 | 
						|
  MOFilename: string;
 | 
						|
 | 
						|
begin
 | 
						|
  Result := '';
 | 
						|
//translate strings - only once?
 | 
						|
  If (Options.Language<>FTranslated) then begin
 | 
						|
    MOFilename:=Format(MOFileTemplate,[Options.Language]);
 | 
						|
    if FileExists(MOFilename) then
 | 
						|
      gettext.TranslateResourceStrings(MoFileName)
 | 
						|
    else begin
 | 
						|
      Result := ('NOTE: unable to find translation file ' + MOFilename);
 | 
						|
      exit;
 | 
						|
    end;
 | 
						|
    // Translate internal documentation strings
 | 
						|
    TranslateDocStrings(Options.Language);
 | 
						|
    FTranslated:=Options.Language;
 | 
						|
  end;
 | 
						|
  // Action is to create the XML skeleton
 | 
						|
  if (Package.Name = '') and (CmdAction<>caUsage) then begin
 | 
						|
    Result := (SNoPackageNameProvided);
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
  if CmdOptions.UpdateMode
 | 
						|
  and (SelectedPackage.Descriptions.IndexOf(Package.Output)<>-1) then begin
 | 
						|
    Result := (SOutputMustNotBeDescr);
 | 
						|
    exit;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetCmdAction(AValue: TCreatorAction);
 | 
						|
begin
 | 
						|
  if FCmdAction=AValue then Exit;
 | 
						|
  FCmdAction:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetDryRun(AValue: boolean);
 | 
						|
begin
 | 
						|
  if FDryRun=AValue then Exit;
 | 
						|
  FDryRun:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetPackage(AValue: TFPDocPackage);
 | 
						|
begin
 | 
						|
  if FPackage=AValue then Exit;
 | 
						|
  FPackage:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.SetWriteProjectFile(AValue: string);
 | 
						|
begin
 | 
						|
  if FWriteProjectFile=AValue then Exit;
 | 
						|
  FWriteProjectFile:=AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.AddDirToFileList(List: TStrings; const ADirName, AMask: String);
 | 
						|
 | 
						|
Var
 | 
						|
  Info : TSearchRec;
 | 
						|
  D, opts : String;
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  i := Pos(',', ADirName);
 | 
						|
  if i > 0 then begin
 | 
						|
    opts := ' ' + Copy(ADirName, i+1, Length(ADirName));
 | 
						|
    D := Copy(ADirName, 1, i-1);
 | 
						|
  end else begin
 | 
						|
    D := ADirName;
 | 
						|
    opts := '';
 | 
						|
  end;
 | 
						|
  if (D<>'') and not DirectoryExists(D) then
 | 
						|
     DoLog('Directory '+D+' does not exist')
 | 
						|
  else
 | 
						|
    begin
 | 
						|
    if (D='.') then
 | 
						|
      D:=''
 | 
						|
    else
 | 
						|
      D:=IncludeTrailingPathDelimiter(D);
 | 
						|
    If (FindFirst(D+AMask,0,Info)=0) then
 | 
						|
      try
 | 
						|
        Repeat
 | 
						|
          If (Info.Attr and faDirectory)=0 then
 | 
						|
            List.Add(D+Info.name + opts);
 | 
						|
        Until FindNext(Info)<>0;
 | 
						|
      finally
 | 
						|
        FindClose(Info);
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.AddToFileList(List: TStrings; const FileName: String);
 | 
						|
var
 | 
						|
  f: Text;
 | 
						|
  s, opts: String;
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  i := Pos(',', FileName);
 | 
						|
  if i > 0 then begin
 | 
						|
    opts := ' ' + Copy(FileName, i+1, Length(FileName));
 | 
						|
    s := Copy(FileName, 1, i-1);
 | 
						|
  end else begin
 | 
						|
    s := FileName;
 | 
						|
    opts := '';
 | 
						|
  end;
 | 
						|
  if s[1] = '@' then
 | 
						|
  begin
 | 
						|
    AssignFile(f, Copy(s, 2, Length(s)));
 | 
						|
    Reset(f);
 | 
						|
    while not EOF(f) do
 | 
						|
    begin
 | 
						|
      ReadLn(f, s);
 | 
						|
      List.Add(s + opts);
 | 
						|
    end;
 | 
						|
    Close(f);
 | 
						|
  end else
 | 
						|
    List.Add(s + opts);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.ParseCommon(var Cmd, Arg: string):  TCreatorAction;
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  if (Cmd = '-h') or (Cmd = '--help') then begin
 | 
						|
    //Usage(0)
 | 
						|
    CmdAction := caUsage;
 | 
						|
    exit(caUsage);
 | 
						|
  end;
 | 
						|
  if Cmd = '--update' then
 | 
						|
    CmdOptions.UpdateMode := True
 | 
						|
  else if (Cmd = '-n') or (Cmd = '--dry-run') then
 | 
						|
    begin
 | 
						|
    DryRun:=True;
 | 
						|
    CmdAction := caDryRun;
 | 
						|
    end
 | 
						|
//project options
 | 
						|
  else if Cmd = '--hide-protected' then
 | 
						|
    Options.HideProtected := True
 | 
						|
  else if Cmd = '--warn-no-node' then
 | 
						|
    Options.WarnNoNode := True
 | 
						|
  else if Cmd = '--show-private' then
 | 
						|
    Options.ShowPrivate := True  //DoDi: was False???
 | 
						|
  else if Cmd = '--stop-on-parser-error' then
 | 
						|
    Options.StopOnParseError := True
 | 
						|
  else if Cmd = '--dont-trim' then
 | 
						|
    Options.DontTrim := True
 | 
						|
  else if Cmd = '--parse-impl' then
 | 
						|
    Options.InterfaceOnly:=false //is default really True???
 | 
						|
  else begin
 | 
						|
  //split option
 | 
						|
    i := Pos('=', Cmd);
 | 
						|
    if i > 0 then begin
 | 
						|
      Arg := Copy(Cmd, i + 1, Length(Cmd));
 | 
						|
      SetLength(Cmd, i - 1);
 | 
						|
      if (Arg <> '') and (Arg[1] = '"') then begin
 | 
						|
      //remove quotes
 | 
						|
        Arg := StringReplace(Arg, '"', '', [rfReplaceAll]);
 | 
						|
      end;
 | 
						|
    end else begin
 | 
						|
      SetLength(Arg, 0);
 | 
						|
      exit(caInvalid); //options without values unhandled here!
 | 
						|
    end;
 | 
						|
  //more options
 | 
						|
    Result := caDefault; //assume succ
 | 
						|
    if (Cmd = '--project') or (Cmd='-p') then begin
 | 
						|
      FProjectFile:=True; //means: project loaded
 | 
						|
      WriteProjectFile := Arg; //do *not* normally overwrite!
 | 
						|
      LoadProjectFile(Arg);
 | 
						|
    end else if (Cmd = '--descr') then begin
 | 
						|
      if FileExists(Arg) then
 | 
						|
        AddToFileList(SelectedPackage.Descriptions, Arg)
 | 
						|
    end else if (Cmd = '--descr-dir') then
 | 
						|
      DescrDir:=Arg
 | 
						|
    else if (Cmd = '-i') or (Cmd = '--input') then
 | 
						|
      AddToFileList(SelectedPackage.Inputs, Arg)
 | 
						|
    else if (Cmd = '--input-dir') then
 | 
						|
      InputDir:=Arg
 | 
						|
    else if Cmd = '--package' then begin
 | 
						|
      If FProjectFile then
 | 
						|
        FPackage:=Packages.FindPackage(Arg)
 | 
						|
      else begin
 | 
						|
        if FPackage = nil then
 | 
						|
          FPackage := (Packages.Add) as TFPDocPackage;
 | 
						|
        FPackage.Name:=Arg;
 | 
						|
      end
 | 
						|
    end else if Cmd = '--ostarget' then
 | 
						|
      Options.OSTarget := Arg
 | 
						|
    else if Cmd = '--cputarget' then
 | 
						|
      Options.CPUTarget := Arg
 | 
						|
    else if (Cmd = '-l') or (Cmd = '--lang') then
 | 
						|
      Options.Language := Arg
 | 
						|
    else if Cmd = '--mo-dir' then
 | 
						|
      Options.modir := Arg
 | 
						|
    else if (Cmd = '-o') or (Cmd = '--output') then
 | 
						|
      SelectedPackage.Output := Arg
 | 
						|
    else if (Cmd = '-v') or (Cmd = '--verbose') then
 | 
						|
      Verbose:=true
 | 
						|
    else if Cmd = '--write-project' then begin
 | 
						|
      CmdAction := caWriteProject;
 | 
						|
      WriteProjectFile:=Arg
 | 
						|
    end
 | 
						|
  //else no match
 | 
						|
    else
 | 
						|
      Result := caInvalid;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDocMaker.ParseFPDocOption(const S: string):  TCreatorAction;
 | 
						|
var
 | 
						|
  Cmd, Arg: String;
 | 
						|
begin
 | 
						|
  Cmd:=S;
 | 
						|
  Arg := ''; //make compiler happy
 | 
						|
  Result := ParseCommon(Cmd, Arg);
 | 
						|
  if Result <> caInvalid then
 | 
						|
    exit;
 | 
						|
  Result := caDefault; //assume succ
 | 
						|
  if (Cmd = '-t') or (Cmd = '--emit-notes') then
 | 
						|
    Options.EmitNotes := True
 | 
						|
  else if Cmd = '--content' then
 | 
						|
    SelectedPackage.ContentFile := Arg
 | 
						|
  else if Cmd = '--import' then
 | 
						|
    SelectedPackage.Imports.Add(Arg)
 | 
						|
//this should not be a project option
 | 
						|
  else if (Cmd = '-f') or (Cmd = '--format') then
 | 
						|
    begin
 | 
						|
    Arg:=UpperCase(Arg);
 | 
						|
    If FindWriterClass(Arg)=-1 then
 | 
						|
      WriteLn(StdErr, Format(SCmdLineInvalidFormat, [Arg]))
 | 
						|
    else
 | 
						|
      Options.BackEnd:=Arg;
 | 
						|
    end
 | 
						|
  else
 | 
						|
    begin
 | 
						|
    Options.BackendOptions.Add(Cmd);
 | 
						|
    Options.BackendOptions.Add(Arg);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.LogToStdOut(Sender: TObject; const msg: string);
 | 
						|
begin
 | 
						|
  WriteLn(msg);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.LogToStdErr(Sender: TObject; const msg: string);
 | 
						|
begin
 | 
						|
  WriteLn(stderr, msg);
 | 
						|
end;
 | 
						|
 | 
						|
(* Write *all* updates into AOutputName (=DescrFile for Create, UpdFile for Update).
 | 
						|
*)
 | 
						|
Function TFPDocMaker.DocumentPackage(Const APackageName,AOutputName: string; InputFiles, DescrFiles : TStrings) : String;
 | 
						|
Var
 | 
						|
  F : Text;
 | 
						|
  I,J : Integer;
 | 
						|
  Engine: TSkelEngine;
 | 
						|
begin
 | 
						|
  Result:='';
 | 
						|
  AssignFile(f, AOutputName);
 | 
						|
  Rewrite(f);
 | 
						|
  Try
 | 
						|
    WriteLn(f, '<?xml version="1.0" encoding="ISO-8859-1"?>');
 | 
						|
    WriteLn(f, '<fpdoc-descriptions>');
 | 
						|
    WriteLn(f, '<package name="', APackageName, '">');
 | 
						|
    I:=0;
 | 
						|
    While (Result='') And (I<InputFiles.Count) do
 | 
						|
      begin
 | 
						|
      Engine := TSkelEngine.Create;
 | 
						|
    //configure engine
 | 
						|
      Engine.OnLog:=Self.OnLog;
 | 
						|
      Engine.ScannerLogEvents:=Self.ScannerLogEvents;
 | 
						|
      Engine.ParserLogEvents:=Self.ParserLogEvents;
 | 
						|
      Engine.Options := CmdOptions;
 | 
						|
      Try
 | 
						|
        Engine.SetPackageName(APackageName);
 | 
						|
        if CmdOptions.UpdateMode then
 | 
						|
          For J:=0 to DescrFiles.Count-1 do
 | 
						|
            Engine.AddDocFile(DescrFiles[J]);
 | 
						|
        Try
 | 
						|
          Engine.DocumentFile(F,InputFiles[i],Options.OSTarget,Options.CPUTarget);
 | 
						|
        except
 | 
						|
          on E:Exception do
 | 
						|
          begin
 | 
						|
            Result:='Error while documenting: '+E.message;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      Finally
 | 
						|
        Engine.Free;
 | 
						|
      end;
 | 
						|
      Inc(I);
 | 
						|
      end;
 | 
						|
  Finally
 | 
						|
    WriteLn(f, '</package>');
 | 
						|
    WriteLn(f, '</fpdoc-descriptions>');
 | 
						|
    Close(f);
 | 
						|
    if Result <> '' then begin
 | 
						|
      DeleteFile(AOutputName); //remove invalid file
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDocMaker.CreateUnitDocumentation(const AUnit: string; ParseOnly: Boolean);
 | 
						|
var
 | 
						|
  il: TStringList;
 | 
						|
  spec: string;
 | 
						|
begin
 | 
						|
  if AUnit <> '' then begin
 | 
						|
  //selected unit only
 | 
						|
    spec := UnitSpec(AUnit);
 | 
						|
    il := TStringList.Create;
 | 
						|
    il.Assign(Package.Inputs);
 | 
						|
    Package.Inputs.Clear;
 | 
						|
    Package.Inputs.Add(spec);
 | 
						|
    try
 | 
						|
      inherited CreateDocumentation(Package, ParseOnly);
 | 
						|
    finally
 | 
						|
      Package.Inputs.Assign(il);
 | 
						|
      il.Free;
 | 
						|
    end;
 | 
						|
  end else begin
 | 
						|
    CreateDocumentation(Package,ParseOnly);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
(* Return True and (try) kill file if no "<element" found.
 | 
						|
*)
 | 
						|
function TFPDocMaker.CleanXML(const FileName: string): boolean;
 | 
						|
var
 | 
						|
  f: TextFile;
 | 
						|
  s: string;
 | 
						|
begin
 | 
						|
  AssignFile(f, FileName);
 | 
						|
  Reset(f);
 | 
						|
  try
 | 
						|
    while not EOF(f) do begin
 | 
						|
      ReadLn(f, s);
 | 
						|
      if Pos('<element ', s) > 0 then
 | 
						|
        exit(False); //file not empty
 | 
						|
    end;
 | 
						|
  finally
 | 
						|
    CloseFile(f);
 | 
						|
  end;
 | 
						|
//nothing found, delete the file
 | 
						|
  if DeleteFile(FileName) then
 | 
						|
    DoLog('File ' + FileName + ' has no elements. Deleted.')
 | 
						|
  else
 | 
						|
    DoLog('File ' + FileName + ' has no elements. Delete failed.');
 | 
						|
  Result := True;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPDocMaker.ParseUpdateOption(const s: String):  TCreatorAction;
 | 
						|
var
 | 
						|
  Cmd, Arg: String;
 | 
						|
begin
 | 
						|
  Cmd:=S;
 | 
						|
  Arg := ''; //make compiler happy
 | 
						|
  Result := ParseCommon(Cmd, Arg);
 | 
						|
  if Result <> caInvalid then
 | 
						|
    exit;
 | 
						|
  Result := caDefault; //assume succ
 | 
						|
  if s = '--disable-arguments' then
 | 
						|
    CmdOptions.DisableArguments := True
 | 
						|
  else if s = '--disable-errors' then
 | 
						|
    CmdOptions.DisableErrors := True
 | 
						|
  else if s = '--disable-function-results' then
 | 
						|
    CmdOptions.DisableFunctionResults := True
 | 
						|
  else if s = '--disable-seealso' then
 | 
						|
    CmdOptions.DisableSeealso := True
 | 
						|
  else if s = '--disable-private' then
 | 
						|
    CmdOptions.DisablePrivate := True
 | 
						|
  else if s = '--disable-override' then
 | 
						|
    CmdOptions.DisableOverride := True
 | 
						|
  else if s = '--disable-protected' then
 | 
						|
    begin
 | 
						|
    CmdOptions.DisableProtected := True;
 | 
						|
    CmdOptions.DisablePrivate :=True;
 | 
						|
    end
 | 
						|
  else if (s = '--emitclassseparator') or (s='--emit-class-separator') then
 | 
						|
    CmdOptions.EmitClassSeparator := True
 | 
						|
  else if (s = '--emit-declaration') then
 | 
						|
    CmdOptions.WriteDeclaration := True
 | 
						|
  else if (s = '--sort-nodes') then
 | 
						|
    CmdOptions.SortNodes := True
 | 
						|
  else if (Cmd = '-i') or (Cmd = '--input') then
 | 
						|
    AddToFileList(SelectedPackage.Inputs, Arg)
 | 
						|
  else if not assigned(OnOption) or not OnOption(Cmd, Arg) then begin
 | 
						|
    DoLog(SCmdLineInvalidOption, [s]);
 | 
						|
    CmdAction := caInvalid;
 | 
						|
    Result := caInvalid;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
end.
 | 
						|
 |