mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 04:01:28 +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.
 | |
| 
 | 
