makeskel.pp 19 KB

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