makeskel.pp 19 KB

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