makeskel.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. {
  2. FPDoc - Free Pascal Documentation Tool
  3. Copyright (C) 2000 - 2003 by
  4. Areca Systems GmbH / Sebastian Guenther, [email protected]
  5. 2005-2012 by
  6. various FPC contributors
  7. * Skeleton XML description file generator.
  8. This generator scans Pascal source code for identifiers and emits XML files
  9. suitable for further processing with the fpdoc documentation system:
  10. users can edit the XML file and add (help) description.
  11. See the file COPYING, included in this distribution,
  12. for details about the copyright.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. }
  17. program MakeSkel;
  18. {$mode objfpc}
  19. {$h+}
  20. uses
  21. fpdocstrs, SysUtils, Classes, Gettext, dGlobals, PasTree, PParser,PScanner;
  22. resourcestring
  23. STitle = 'MakeSkel - FPDoc skeleton XML description file generator';
  24. SVersion = 'Version %s [%s]';
  25. SCmdLineHelp = 'See documentation for usage.';
  26. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  27. SNoPackageNameProvided = 'Please specify a package name with --package=<name>';
  28. SOutputMustNotBeDescr = 'Output file must be different from description filenames.';
  29. SCreatingNewNode = 'Creating documentation for new node : %s';
  30. SNodeNotReferenced = 'Documentation node "%s" no longer used';
  31. SDone = 'Done.';
  32. type
  33. TCmdLineAction = (actionHelp, actionConvert);
  34. TNodePair = Class(TObject)
  35. Private
  36. FEl : TPasElement;
  37. FNode : TDocNode;
  38. Public
  39. Constructor Create(AnElement : TPasElement; ADocNode : TDocNode);
  40. Property Element : TPasElement Read FEl;
  41. Property DocNode : TDocNode Read FNode;
  42. end;
  43. { TSkelEngine }
  44. TSkelEngine = class(TFPDocEngine)
  45. Private
  46. FEmittedList,
  47. FNodeList,
  48. FModules : TStringList;
  49. Procedure DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
  50. function EffectiveVisibility(El: TPasElement): TPasMemberVisibility;
  51. public
  52. Destructor Destroy; override;
  53. Function MustWriteElement(El : TPasElement; Full : Boolean) : Boolean;
  54. Function WriteElement(Var F : Text; El : TPasElement; ADocNode : TDocNode) : Boolean;
  55. function FindModule(const AName: String): TPasModule; override;
  56. function CreateElement(AClass: TPTreeElement; const AName: String;
  57. AParent: TPasElement; AVisibility :TPasMemberVisibility;
  58. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override;
  59. procedure WriteUnReferencedNodes;
  60. Procedure WriteNodes(Var F : Text; AModule : TPasModule; List : TStrings);
  61. Procedure DocumentFile(Var F : Text; Const AFileName,ATarget,ACPU : String);
  62. Property NodeList : TStringList Read FNodeList;
  63. Property EmittedList : TStringList Read FEmittedList;
  64. end;
  65. const
  66. CmdLineAction: TCmdLineAction = actionConvert;
  67. OSTarget: String = {$I %FPCTARGETOS%};
  68. CPUTarget: String = {$I %FPCTARGETCPU%};
  69. FPCVersion: String = {$I %FPCVERSION%};
  70. FPCDate: String = {$I %FPCDATE%};
  71. var
  72. WriteDeclaration,
  73. UpdateMode,
  74. SortNodes,
  75. DisableOverride,
  76. DisableErrors,
  77. DisableSeealso,
  78. DisableArguments,
  79. DisableProtected,
  80. DisablePrivate,
  81. DisableFunctionResults: Boolean;
  82. EmitClassSeparator: Boolean;
  83. Constructor TNodePair.Create(AnElement : TPasElement; ADocNode : TDocNode);
  84. begin
  85. Fel:=Anelement;
  86. FNode:=ADocNode;
  87. end;
  88. function TSkelEngine.FindModule(const AName: String): TPasModule;
  89. Var
  90. I : Integer;
  91. begin
  92. Result:=Inherited FindModule(AName);
  93. If (Result=Nil) then
  94. begin // Create dummy list and search in that.
  95. If (FModules=Nil) then
  96. begin
  97. FModules:=TStringList.Create;
  98. FModules.Sorted:=True;
  99. end;
  100. I:=FModules.IndexOf(AName);
  101. IF (I=-1) then
  102. begin
  103. Result:=TPasModule.Create(AName,Nil);
  104. FModules.AddObject(AName,Result);
  105. end
  106. else
  107. Result:=FModules.Objects[i] as TPasModule;
  108. end;
  109. end;
  110. Destructor TSkelEngine.Destroy;
  111. Var
  112. I : Integer;
  113. begin
  114. If Assigned(FModules) then
  115. begin
  116. { For I:=0 to FModules.Count-1 do
  117. FModules.Objects[i].Release;}
  118. FreeAndNil(FModules);
  119. end;
  120. end;
  121. Function TSkelEngine.EffectiveVisibility (El : TPasElement) : TPasMemberVisibility;
  122. Var
  123. V : TPasMemberVisibility;
  124. begin
  125. Result:=EL.Visibility;
  126. El:=el.Parent;
  127. While Assigned(El) do
  128. begin
  129. V:=EL.Visibility;
  130. if V=visStrictPrivate then
  131. V:=visPrivate
  132. else if V=visStrictProtected then
  133. V:=visProtected;
  134. if (V<>visDefault) and ((V<Result) or (Result=visDefault)) then
  135. Result:=V;
  136. EL:=el.Parent;
  137. end;
  138. end;
  139. Function TSkelEngine.MustWriteElement(El : TPasElement; Full : Boolean) : Boolean;
  140. Var
  141. VisibilityOK : Boolean;
  142. V : TPasMemberVisibility;
  143. begin
  144. V:=EffectiveVisibility(El);
  145. Case V of
  146. visPrivate,visStrictPrivate:
  147. VisibilityOK:= not DisablePrivate;
  148. visProtected,visStrictProtected:
  149. VisibilityOK:= not DisableProtected;
  150. else
  151. VisibilityOK:=True;
  152. end;
  153. Result:= Assigned(el.Parent)
  154. and (Length(El.Name) > 0)
  155. and VisibilityOK
  156. and (Not (El is TPasExpr))
  157. and (not DisableArguments or (El.ClassType <> TPasArgument))
  158. and (not DisableFunctionResults or (El.ClassType <> TPasResultElement));
  159. If Result and Full then
  160. begin
  161. Result:=(Not Assigned(FEmittedList) or (FEmittedList.IndexOf(El.FullName)=-1));
  162. If DisableOverride and (El is TPasProcedure) then
  163. Result:=Not TPasProcedure(El).IsOverride;
  164. end;
  165. end;
  166. function TSkelEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  167. AParent: TPasElement; AVisibility : TPasMemberVisibility;
  168. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  169. Var
  170. DN : TDocNode;
  171. begin
  172. Result := AClass.Create(AName, AParent);
  173. Result.Visibility:=AVisibility;
  174. // Let function/procedure arguments and function results
  175. // inherit visibility from their parents if visDefault visibility is
  176. // specified.
  177. // This allows easier text searches on visibility in the resulting XML
  178. if (AVisibility=visDefault) and
  179. ((Result is TPasArgument) or (Result is TPasResultElement)) then
  180. Result.Visibility:=AParent.Visibility;
  181. if AClass.InheritsFrom(TPasModule) then
  182. CurModule := TPasModule(Result);
  183. // Track this element
  184. If UpdateMode then
  185. begin
  186. DN:=FindDocNode(Result);
  187. If Assigned(DN) then
  188. DN.IncRefCount;
  189. end
  190. else
  191. DN:=Nil;
  192. // See if we need to write documentation for it
  193. If MustWriteElement(Result,False) then
  194. FNodeList.AddObject(Result.PathName,TNodePair.Create(Result,DN));
  195. end;
  196. Function TSkelEngine.WriteElement(Var F : Text;El : TPasElement; ADocNode : TDocNode) : Boolean;
  197. Function WriteOnlyShort(APasElement : TPasElement) : Boolean;
  198. begin
  199. Result:=(APasElement.ClassType=TPasArgument) or
  200. (APasElement.ClassType=TPasResultElement) or
  201. (APasElement.ClassType=TPasEnumValue) or
  202. (aPaselement.ClassType=TPasUsesUnit) or
  203. ((APasElement.CLassType=TPasVariable) and (APasElement.Parent is TPasRecordType));
  204. end;
  205. Function IsTypeVarConst(APasElement : TPasElement) : Boolean;
  206. begin
  207. With APasElement do
  208. Result:=(InheritsFrom(TPasType) and not InheritsFrom(TPasClassType)) or
  209. (InheritsFrom(TPasResString)) or
  210. (InheritsFrom(TPasVariable));
  211. end;
  212. Function NeedDeclaration(El : TPasElement) : boolean;
  213. begin
  214. Result:=IsTypeVarConst(El)
  215. or WriteOnlyShort(El)
  216. or EL.InheritsFrom(TPasProcedure)
  217. end;
  218. begin
  219. // Check again, this time with full declaration.
  220. Result:=MustWriteElement(El,True);
  221. If Result and UpdateMode then
  222. Result:=(ADocNode=Nil);
  223. If Not Result Then
  224. Exit;
  225. If UpdateMode then
  226. Writeln(stderr,Format(ScreatingNewNode,[el.PathName]));
  227. FEmittedList.Add(El.FullName); // So we don't emit again.
  228. WriteLn(f);
  229. if EmitClassSeparator and (El.ClassType = TPasClassType) then
  230. begin
  231. WriteLn(f, '<!--');
  232. WriteLn(f, ' ********************************************************************');
  233. WriteLn(f, ' ', El.PathName);
  234. WriteLn(f, ' ********************************************************************');
  235. WriteLn(f, '-->');
  236. WriteLn(f);
  237. end;
  238. If Not (WriteDeclaration and NeedDeclaration(El)) then
  239. Writeln(F,'<!-- ', El.ElementTypeName,' Visibility: ',VisibilityNames[El.Visibility], ' -->')
  240. else
  241. begin
  242. Writeln(F,'<!-- ',El.ElementTypeName,' Visibility: ',VisibilityNames[El.Visibility]);
  243. Writeln(F,' Declaration: ',El.GetDeclaration(True),' -->');
  244. end;
  245. WriteLn(f,'<element name="', El.FullName, '">');
  246. WriteLn(f, '<short></short>');
  247. if Not WriteOnlyShort(El) then
  248. begin
  249. WriteLn(f, '<descr>');
  250. WriteLn(f, '</descr>');
  251. if not (DisableErrors or IsTypeVarConst(El)) then
  252. begin
  253. WriteLn(f, '<errors>');
  254. WriteLn(f, '</errors>');
  255. end;
  256. if not DisableSeealso then
  257. begin
  258. WriteLn(f, '<seealso>');
  259. WriteLn(f, '</seealso>');
  260. end;
  261. end;
  262. WriteLn(f, '</element>');
  263. end;
  264. Procedure TSkelEngine.DoWriteUnReferencedNodes(N : TDocNode; NodePath : String);
  265. begin
  266. If (N<>Nil) then
  267. begin
  268. If (NodePath<>'') then
  269. NodePath:=NodePath+'.';
  270. DoWriteUnReferencedNodes(N.FirstChild,NodePath+N.Name);
  271. While (N<>Nil) do
  272. begin
  273. if (N.RefCount=0) and (N.Node<>Nil) and (Not N.TopicNode) then
  274. Writeln(stderr,Format(SNodeNotReferenced,[NodePath+N.Name]));
  275. N:=N.NextSibling;
  276. end;
  277. end;
  278. end;
  279. procedure TSkelEngine.WriteUnReferencedNodes;
  280. begin
  281. DoWriteUnReferencedNodes(RootDocNode,'');
  282. end;
  283. Procedure TSkelEngine.WriteNodes(Var F : Text; AModule : TPasModule; List : TStrings);
  284. Var
  285. P : TNodePair;
  286. I : integer;
  287. begin
  288. WriteLn(f);
  289. WriteLn(f, '<!--');
  290. WriteLn(f, ' ====================================================================');
  291. WriteLn(f, ' ', Amodule.Name);
  292. WriteLn(f, ' ====================================================================');
  293. WriteLn(f, '-->');
  294. WriteLn(f);
  295. WriteLn(f, '<module name="', AModule.Name, '">');
  296. if not UpdateMode then
  297. begin
  298. WriteLn(f, '<short></short>');
  299. WriteLn(f, '<descr>');
  300. WriteLn(f, '</descr>');
  301. end;
  302. Try
  303. For I:=0 to List.Count-1 do
  304. begin
  305. P:=List.Objects[i] as TNodePair;
  306. If (P.Element<>AModule) then
  307. WriteElement(F,P.Element,P.DocNode);
  308. end;
  309. Finally
  310. WriteLn(f, '');
  311. WriteLn(f, '</module> <!-- ', AModule.Name, ' -->');
  312. WriteLn(f, '');
  313. end;
  314. end;
  315. Procedure TSkelEngine.DocumentFile(Var F : Text; Const AFileName,ATarget,ACPU : String);
  316. Procedure ResolveOperators;
  317. Var
  318. E : TPasElement;
  319. P : TNodePair;
  320. N : TDocNode;
  321. I : integer;
  322. begin
  323. For I:=0 to FNodeList.Count-1 do
  324. begin
  325. P:=TNodePair(FNodeList.Objects[i]);
  326. if P.Element.InheritsFrom(TPasOperator) then
  327. begin
  328. N:=FindDocNode(P.Element);
  329. If Assigned(N) then
  330. N.IncRefCount;
  331. P.FNode:=N;
  332. end;
  333. end;
  334. end;
  335. Var
  336. Module : TPasModule;
  337. I : Integer;
  338. N : TDocNode;
  339. begin
  340. // wrong because afilename is a cmdline with other options. Straight testing filename is therefore wrong.
  341. // if not(FileExists(AFileName)) then
  342. // raise Exception.CreateFmt('Cannot find source file %s to document.',[AFileName]);
  343. FNodeList:=TStringList.Create;
  344. Try
  345. FEmittedList:=TStringList.Create;
  346. FEmittedList.Sorted:=True;
  347. try
  348. Module:=ParseSource (Self,AFileName+' -dFPC',ATarget,ACPU,[poUseStreams,poSkipDefaultDefs]);
  349. If UpdateMode then
  350. begin
  351. N:=FindDocNode(Module);
  352. If Assigned(N) then
  353. N.IncRefCount;
  354. ResolveOperators;
  355. end;
  356. If SortNodes then
  357. FNodelist.Sorted:=True;
  358. WriteNodes(F,Module,FNodeList);
  359. If UpdateMode then
  360. WriteUnReferencedNodes;
  361. Finally
  362. FEmittedList.Free;
  363. end;
  364. Finally
  365. For I:=0 to FNodeList.Count-1 do
  366. FNodeList.Objects[i].Free;
  367. FNodeList.Free;
  368. end;
  369. end;
  370. { ---------------------------------------------------------------------
  371. Main program. Document all units.
  372. ---------------------------------------------------------------------}
  373. Function DocumentPackage(Const APackageName,AOutputName : String; InputFiles,DescrFiles : TStrings) : String;
  374. Var
  375. F : Text;
  376. I,J : Integer;
  377. Engine: TSkelEngine;
  378. begin
  379. Result:='';
  380. Assign(f, AOutputName);
  381. Rewrite(f);
  382. Try
  383. WriteLn(f, '<?xml version="1.0" encoding="ISO-8859-1"?>');
  384. WriteLn(f, '<fpdoc-descriptions>');
  385. WriteLn(f, '<package name="', APackageName, '">');
  386. Try
  387. I:=0;
  388. While (Result='') And (I<InputFiles.Count) do
  389. begin
  390. Engine := TSkelEngine.Create;
  391. Try
  392. Engine.SetPackageName(APackageName);
  393. if UpdateMode then
  394. For J:=0 to DescrFiles.Count-1 do
  395. Engine.AddDocFile(DescrFiles[J]);
  396. Try
  397. Engine.DocumentFile(F,InputFiles[I],OSTarget,CPUTarget);
  398. except
  399. on E:Exception do
  400. begin
  401. WriteLn('Error while documenting: '+E.message);
  402. Result:='Error while documenting: '+E.message;
  403. end;
  404. end;
  405. Finally
  406. Engine.Free;
  407. end;
  408. Inc(I);
  409. end;
  410. Finally
  411. WriteLn(f, '</package>');
  412. WriteLn(f, '</fpdoc-descriptions>');
  413. end;
  414. finally
  415. Close(f);
  416. end;
  417. end;
  418. { ---------------------------------------------------------------------
  419. Option management
  420. ---------------------------------------------------------------------}
  421. var
  422. InputFiles,
  423. DescrFiles : TStringList;
  424. DocLang : String;
  425. PackageName,
  426. OutputName: String;
  427. procedure InitOptions;
  428. begin
  429. InputFiles := TStringList.Create;
  430. DescrFiles := TStringList.Create;
  431. end;
  432. procedure FreeOptions;
  433. begin
  434. DescrFiles.Free;
  435. InputFiles.Free;
  436. end;
  437. procedure ParseOption(const s: String);
  438. procedure AddToFileList(List: TStringList; const FileName: String);
  439. var
  440. f: Text;
  441. s: String;
  442. begin
  443. if Copy(FileName, 1, 1) = '@' then
  444. begin
  445. Assign(f, Copy(FileName, 2, Length(FileName)));
  446. Reset(f);
  447. while not EOF(f) do
  448. begin
  449. ReadLn(f, s);
  450. List.Add(s);
  451. end;
  452. Close(f);
  453. end else
  454. List.Add(FileName);
  455. end;
  456. var
  457. i: Integer;
  458. Cmd, Arg: String;
  459. begin
  460. if (s = '-h') or (s = '--help') then
  461. CmdLineAction := actionHelp
  462. else if s = '--update' then
  463. UpdateMode := True
  464. else if s = '--disable-arguments' then
  465. DisableArguments := True
  466. else if s = '--disable-errors' then
  467. DisableErrors := True
  468. else if s = '--disable-function-results' then
  469. DisableFunctionResults := True
  470. else if s = '--disable-seealso' then
  471. DisableSeealso := True
  472. else if s = '--disable-private' then
  473. DisablePrivate := True
  474. else if s = '--disable-override' then
  475. DisableOverride := True
  476. else if s = '--disable-protected' then
  477. begin
  478. DisableProtected := True;
  479. DisablePrivate :=True;
  480. end
  481. else if (s = '--emitclassseparator') or (s='--emit-class-separator') then
  482. EmitClassSeparator := True
  483. else if (s = '--emit-declaration') then
  484. WriteDeclaration := True
  485. else if (s = '--sort-nodes') then
  486. SortNodes := True
  487. else
  488. begin
  489. i := Pos('=', s);
  490. if i > 0 then
  491. begin
  492. Cmd := Copy(s, 1, i - 1);
  493. Arg := Copy(s, i + 1, Length(s));
  494. end else
  495. begin
  496. Cmd := s;
  497. SetLength(Arg, 0);
  498. end;
  499. if (Cmd = '-i') or (Cmd = '--input') then
  500. AddToFileList(InputFiles, Arg)
  501. else if (Cmd = '-l') or (Cmd = '--lang') then
  502. DocLang := Arg
  503. else if (Cmd = '-o') or (Cmd = '--output') then
  504. OutputName := Arg
  505. else if Cmd = '--package' then
  506. PackageName := Arg
  507. else if Cmd = '--descr' then
  508. begin
  509. if FileExists(Arg) then
  510. DescrFiles.Add(Arg);
  511. end
  512. else
  513. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  514. end;
  515. end;
  516. Function ParseCommandLine : Integer;
  517. Const
  518. {$IFDEF Unix}
  519. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  520. {$ELSE}
  521. MoFileTemplate ='intl/makeskel.%s.mo';
  522. {$ENDIF}
  523. var
  524. MOFilename: string;
  525. i: Integer;
  526. begin
  527. Result:=0;
  528. DocLang:='';
  529. for i := 1 to ParamCount do
  530. ParseOption(ParamStr(i));
  531. If (DocLang<>'') then
  532. begin
  533. MOFilename:=Format(MOFileTemplate,[DocLang]);
  534. if FileExists(MOFilename) then
  535. gettext.TranslateResourceStrings(MoFileName)
  536. else
  537. writeln('NOTE: unable to find translation file ',MOFilename);
  538. // Translate internal documentation strings
  539. TranslateDocStrings(DocLang);
  540. end;
  541. // Action is to create the XML skeleton
  542. if (Length(PackageName) = 0) and (CmdLineAction<>ActionHelp) then
  543. begin
  544. WriteLn(SNoPackageNameProvided);
  545. Result:=2;
  546. end;
  547. if DescrFiles.IndexOf(OutputName)<>-1 then
  548. begin
  549. Writeln(SOutputMustNotBeDescr);
  550. Result:=3;
  551. end;
  552. end;
  553. { ---------------------------------------------------------------------
  554. Usage
  555. ---------------------------------------------------------------------}
  556. Procedure Usage;
  557. begin
  558. Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
  559. Writeln('Where [options] is one or more of :');
  560. Writeln(' --descr=filename Filename for update.');
  561. Writeln(' --disable-arguments Do not create nodes for function arguments.');
  562. Writeln(' --disable-errors Do not create errors node.');
  563. Writeln(' --disable-function-results');
  564. Writeln(' Do not create nodes for function arguments.');
  565. Writeln(' --disable-override Do not create nodes for override methods.');
  566. Writeln(' --disable-private Do not create nodes for class private fields.');
  567. Writeln(' --disable-protected Do not create nodes for class protected fields.');
  568. Writeln(' --disable-seealso Do not create seealso node.');
  569. Writeln(' --emit-class-separator');
  570. Writeln(' Emit descriptive comment between classes.');
  571. Writeln(' --emit-declaration Emit declaration for elements.');
  572. Writeln(' --help Emit help.');
  573. Writeln(' --input=cmdline Input file to create skeleton for.');
  574. Writeln(' Use options are as for compiler.');
  575. Writeln(' --lang=language Use selected language.');
  576. Writeln(' --output=filename Send output to file.');
  577. Writeln(' --package=name Specify package name (mandatory).');
  578. Writeln(' --sort-nodes Sort element nodes (not modules)');
  579. Writeln(' --update Update mode. Output only missing nodes.');
  580. end;
  581. { ---------------------------------------------------------------------
  582. Main Program
  583. ---------------------------------------------------------------------}
  584. Procedure Run;
  585. var
  586. E: Integer;
  587. begin
  588. WriteLn(STitle);
  589. WriteLn(Format(SVersion, [FPCVersion, FPCDate]));
  590. WriteLn(SCopyright1);
  591. WriteLn(SCopyright2);
  592. InitOptions;
  593. Try
  594. E:=ParseCommandLine;
  595. If E<>0 then
  596. Halt(E);
  597. WriteLn;
  598. if CmdLineAction = actionHelp then
  599. Usage
  600. else
  601. begin
  602. DocumentPackage(PackageName,OutputName,InputFiles,DescrFiles);
  603. WriteLn(SDone);
  604. end;
  605. Finally
  606. FreeOptions;
  607. end;
  608. end;
  609. Begin
  610. Run;
  611. end.