2
0

fpclasschart.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. {
  2. FPClass chart - Free Pascal class chart generation tool
  3. Copyright (c) 2008 - Michael Van Canneyt, [email protected]
  4. * Free Pascal class chart generation tool
  5. See the file COPYING, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. {$mode objfpc}
  12. {$h+}
  13. program fpclasschart;
  14. uses
  15. SysUtils, Classes, Typinfo, Gettext, dom, xmlread,
  16. dGlobals, PasTree, PParser,PScanner, xmlwrite, fpdocclasstree;
  17. resourcestring
  18. STitle = 'fpClassTree - Create class tree from pascal sources';
  19. SVersion = 'Version %s [%s]';
  20. SCopyright = '(c) 2008 - Michael Van Canneyt, [email protected]';
  21. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  22. SDone = 'Done.';
  23. SSkipMerge = 'Cannot merge %s into %s tree.';
  24. SErrNoSuchMergeFile = 'Merge file %s does not exist.';
  25. SMergedFile = 'Merged %d classes from file %s.';
  26. SClassesAdded = 'Added %d classes from %d files.';
  27. type
  28. { TClassTreeEngine }
  29. TClassTreeEngine = class(TFPDocEngine)
  30. Private
  31. FTree : TClassTreeBuilder;
  32. FObjects : TStringList;
  33. public
  34. Constructor Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind);
  35. Destructor Destroy; override;
  36. function CreateElement(AClass: TPTreeElement; const AName: String;
  37. AParent: TPasElement; AVisibility :TPasMemberVisibility;
  38. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override;
  39. end;
  40. { TClassChartFormatter }
  41. TClassMode = (cmNormal,cmSubClass,cmheadClass,cmFirstClass);
  42. TClassChartFormatter = Class (TObject)
  43. private
  44. FClassMode: TClassMode;
  45. FClassTree: TXMLDocument;
  46. FCurrentColCount: Integer;
  47. FCurrentRowCount: Integer;
  48. FFileName: String;
  49. FLargeHeadClassObjects: TStrings;
  50. FLevel: Integer;
  51. FMaxObjectsPerColumn: Integer;
  52. FStartColumnObjects: TStrings;
  53. Protected
  54. procedure FirstClass(E : TDomElement); virtual;
  55. procedure DoEmitClass(E : TDomElement); virtual;
  56. procedure DoHeadClass(E: TDomElement); virtual;
  57. procedure DoNextColumn(E: TDomElement); virtual;
  58. procedure EndSubClass(E: TDomElement; HasSiblings : Boolean); virtual;
  59. procedure StartSubClass(E: TDomElement); virtual;
  60. Procedure StartChart; virtual;
  61. Procedure EndChart; virtual;
  62. procedure EmitClass(E : TDomElement; HasSiblings : Boolean);
  63. Public
  64. Constructor Create (AXML : TXMLDocument); virtual;
  65. Destructor Destroy; override;
  66. Procedure CreateChart;
  67. Property CurrentColCount : Integer Read FCurrentColCount;
  68. Property CurrentRowCount : Integer Read FCurrentRowCount;
  69. Property ClassTree : TXMLDocument Read FClassTree;
  70. Property Level : Integer Read FLevel Write FLevel;
  71. Property ClassMode : TClassMode Read FClassMode;
  72. Published
  73. Property FileName : String Read FFileName Write FFilename;
  74. Property StartColumnObjects : TStrings Read FStartColumnObjects;
  75. Property LargeHeadClassObjects : TStrings Read FLargeHeadClassObjects;
  76. Property MaxObjectsPerColumn : Integer Read FMaxObjectsPerColumn Write FMaxObjectsPerColumn;
  77. end;
  78. { TClassTreeBuilder }
  79. { TChartFormatter }
  80. constructor TClassChartFormatter.Create(AXML: TXMLDocument);
  81. begin
  82. FClassTree:=AXML;
  83. MaxObjectsPerColumn:=60;
  84. FStartColumnObjects:=TStringList.Create;
  85. FLargeHeadClassObjects:=TStringList.Create;
  86. FLargeHeadClassObjects.Add('TPersistent');
  87. FLargeHeadClassObjects.Add('TComponent');
  88. end;
  89. destructor TClassChartFormatter.Destroy;
  90. begin
  91. FreeAndNil(FStartColumnObjects);
  92. FreeAndNil(FLargeHeadClassObjects);
  93. Inherited;
  94. end;
  95. procedure TClassChartFormatter.CreateChart;
  96. Var
  97. N : TDomNode;
  98. E : TDomElement;
  99. I : Integer;
  100. L : TFPList;
  101. begin
  102. (FStartColumnObjects as TStringList).Sorted:=False;
  103. (FLargeHeadClassObjects as TStringList).Sorted:=False;
  104. StartChart;
  105. try
  106. N:=FClassTree.DocumentElement.FirstChild;
  107. FCurrentColCount:=0;
  108. FCurrentRowCount:=0;
  109. FLevel:=0;
  110. L:=TFPList.Create;
  111. try
  112. While (N<>nil) do
  113. begin
  114. If (N.NodeType=ELEMENT_NODE) then
  115. L.Add(N);
  116. N:=N.NextSibling;
  117. end;
  118. If (L.Count>0) then
  119. begin
  120. FirstClass(TDomElement(L[0]));
  121. For I:=0 to L.Count-1 do
  122. EmitClass(TDomElement(L[i]),I<L.Count-1);
  123. end;
  124. finally
  125. L.Free;
  126. end;
  127. L:=TFPList.Create;
  128. try
  129. For I:=0 to FLargeHeadClassObjects.Count-1 do
  130. If Assigned(FLargeHeadClassObjects.Objects[i]) then
  131. L.Add(FLargeHeadClassObjects.Objects[i]);
  132. FLargeHeadClassObjects.Clear;
  133. For I:=0 to L.Count-1 do
  134. begin
  135. E:= TDomElement(L[i]);
  136. DoHeadClass(E);
  137. EmitClass(E,I<L.Count-1);
  138. end;
  139. finally
  140. L.Free;
  141. end;
  142. finally
  143. EndChart;
  144. end;
  145. end;
  146. procedure TClassChartFormatter.FirstClass(E : TDomElement);
  147. begin
  148. FClassMode:=cmFirstClass;
  149. end;
  150. procedure TClassChartFormatter.DoEmitClass(E : TDomElement);
  151. begin
  152. //Reset
  153. FClassMode:=cmNormal;
  154. end;
  155. procedure TClassChartFormatter.DoHeadClass(E : TDomElement);
  156. begin
  157. DoNextColumn(E);
  158. FClassMode:=cmHeadClass;
  159. // Do nothing
  160. end;
  161. procedure TClassChartFormatter.StartSubClass(E : TDomElement);
  162. begin
  163. FClassMode:=cmSubClass;
  164. end;
  165. procedure TClassChartFormatter.EndSubClass(E : TDomElement; HasSiblings : Boolean);
  166. begin
  167. FClassMode:=cmNormal;
  168. end;
  169. procedure TClassChartFormatter.DoNextColumn(E : TDomElement);
  170. begin
  171. Inc(FCurrentColCount);
  172. FCurrentRowCount:=0;
  173. end;
  174. procedure TClassChartFormatter.StartChart;
  175. begin
  176. // Do nothing
  177. end;
  178. procedure TClassChartFormatter.EndChart;
  179. begin
  180. // Do nothing
  181. end;
  182. procedure TClassChartFormatter.EmitClass(E : TDomElement; HasSiblings: Boolean);
  183. Var
  184. N : TDomNode;
  185. I : Integer;
  186. L : TFPList;
  187. begin
  188. Inc(Flevel);
  189. try
  190. I:=FStartColumnObjects.IndexOf(E.NodeName);
  191. if (-1<>I) or ((FCurrentRowCount>MaxObjectsPerColumn) and (FLevel=2)) then
  192. DoNextColumn(E)
  193. else
  194. begin
  195. I:=FLargeHeadClassObjects.IndexOf(E.NodeName);
  196. if (-1<>I) then
  197. begin
  198. FLargeHeadClassObjects.Objects[i]:=E;
  199. Exit; // Must be picked up later.
  200. end;
  201. end;
  202. DoEmitClass(E);
  203. N:=E.FirstChild;
  204. L:=TFPList.Create;
  205. try
  206. While (N<>Nil) do
  207. begin
  208. if (N.NodeType=ELEMENT_NODE) then
  209. L.Add(N);
  210. N:=N.NextSibling;
  211. end;
  212. If L.Count>0 then
  213. begin
  214. StartSubClass(TDomElement(L[0]));
  215. For I:=0 to L.Count-1 do
  216. begin
  217. EmitClass(TDomElement(L[i]),I<L.Count-1);
  218. FClassMode:=cmNormal;
  219. end;
  220. EndSubClass(E,HasSiblings);
  221. end;
  222. Finally
  223. L.Free;
  224. end;
  225. Inc(FCurrentRowCount);
  226. finally
  227. Dec(Flevel);
  228. end;
  229. end;
  230. Type
  231. { TPostScriptClassChartFormatter }
  232. TPostScriptClassChartFormatter = Class(TClassChartFormatter)
  233. FFile : Text;
  234. FMode : TClassMode;
  235. FIndent : Integer;
  236. Procedure EmitLine(S : String);
  237. Protected
  238. procedure DoEmitClass(E : TDomElement); override;
  239. procedure DoNextColumn(E: TDomElement); override;
  240. procedure DoHeadClass(E: TDomElement); override;
  241. procedure StartSubClass(E: TDomElement); override;
  242. procedure EndSubClass(E: TDomElement; HasSiblings : Boolean); override;
  243. Procedure StartChart; override;
  244. Procedure EndChart; override;
  245. end;
  246. { TPostScriptClassChartFormatter }
  247. procedure TPostScriptClassChartFormatter.EmitLine(S: String);
  248. begin
  249. Writeln(FFile,StringofChar(' ',Findent*2),S);
  250. end;
  251. procedure TPostScriptClassChartFormatter.DoEmitClass(E: TDomElement);
  252. begin
  253. Case ClassMode of
  254. cmFirstClass : EmitLine(Format('(%s) Ready drawlargebox',[E.NodeName]));
  255. cmNormal : EmitLine(Format('(%s) Ready newclass',[E.NodeName]));
  256. cmSubClass : EmitLine(Format('(%s) Ready newchildclass',[E.NodeName]));
  257. cmHeadClass : EmitLine(Format('(%s) Ready newlargeheadclass',[E.NodeName]));
  258. end;
  259. end;
  260. procedure TPostScriptClassChartFormatter.DoNextColumn(E: TDomElement);
  261. begin
  262. Inherited;
  263. FIndent:=0;
  264. EmitLine('newcolumn');
  265. end;
  266. procedure TPostScriptClassChartFormatter.DoHeadClass(E: TDomElement);
  267. begin
  268. // DoNextColumn(E);
  269. inherited DoHeadClass(E);
  270. end;
  271. procedure TPostScriptClassChartFormatter.EndSubClass(E: TDomElement; HasSiblings : Boolean);
  272. begin
  273. if HasSiblings then
  274. EmitLine('onelevelback')
  275. else
  276. EmitLine('onelevelbackempty');
  277. If FIndent>0 then
  278. Dec(Findent);
  279. end;
  280. procedure TPostScriptClassChartFormatter.StartSubClass(E: TDomElement);
  281. begin
  282. inherited StartSubClass(E);
  283. Inc(Findent);
  284. end;
  285. procedure TPostScriptClassChartFormatter.StartChart;
  286. begin
  287. Assign(FFile,FileName);
  288. Rewrite(FFile);
  289. end;
  290. procedure TPostScriptClassChartFormatter.EndChart;
  291. begin
  292. Close(FFile);
  293. end;
  294. type
  295. { TGraphVizClassChartFormatter }
  296. TGraphVizClassChartFormatter = class(TClassChartFormatter)
  297. FFile : Text;
  298. FMode : TClassMode;
  299. FIndent : integer;
  300. Procedure EmitLine(S : string);
  301. Protected
  302. procedure DoEmitClass(E : TDomElement); override;
  303. procedure DoNextColumn(E: TDomElement); override;
  304. procedure DoHeadClass(E: TDomElement); override;
  305. procedure StartSubClass(E: TDomElement); override;
  306. procedure EndSubClass(E: TDomElement; HasSiblings : Boolean); override;
  307. Procedure StartChart; override;
  308. Procedure EndChart; override;
  309. end;
  310. { TGraphVizClassChartFormatter }
  311. procedure TGraphVizClassChartFormatter.EmitLine(S: String);
  312. begin
  313. Writeln(FFile,StringofChar(' ',Findent*2),S);
  314. end;
  315. procedure TGraphVizClassChartFormatter.DoEmitClass(E: TDomElement);
  316. begin
  317. Case ClassMode of
  318. cmFirstClass : EmitLine(Format('%s -> %s', [E.ParentNode.NodeName, E.NodeName]));
  319. cmNormal : EmitLine(Format('%s -> %s', [E.ParentNode.NodeName, E.NodeName]));
  320. cmSubClass : EmitLine(Format('%s -> %s', [E.ParentNode.NodeName, E.NodeName]));
  321. cmHeadClass : EmitLine(Format('%s -> %s', [E.ParentNode.NodeName, E.NodeName]));
  322. end;
  323. end;
  324. procedure TGraphVizClassChartFormatter.DoNextColumn(E: TDomElement);
  325. begin
  326. Inherited;
  327. FIndent:=0;
  328. end;
  329. procedure TGraphVizClassChartFormatter.DoHeadClass(E: TDomElement);
  330. begin
  331. // DoNextColumn(E);
  332. inherited DoHeadClass(E);
  333. end;
  334. procedure TGraphVizClassChartFormatter.EndSubClass(E: TDomElement; HasSiblings : Boolean);
  335. begin
  336. If FIndent>0 then
  337. Dec(Findent);
  338. end;
  339. procedure TGraphVizClassChartFormatter.StartSubClass(E: TDomElement);
  340. begin
  341. inherited StartSubClass(E);
  342. Inc(Findent);
  343. end;
  344. procedure TGraphVizClassChartFormatter.StartChart;
  345. begin
  346. Assign(FFile,FileName);
  347. Rewrite(FFile);
  348. EmitLine('digraph G {');
  349. end;
  350. procedure TGraphVizClassChartFormatter.EndChart;
  351. begin
  352. EmitLine('}');
  353. Close(FFile);
  354. end;
  355. Type
  356. TOutputFormat = (ofXML,ofPostscript, ofGraphViz);
  357. Var
  358. OutputFormat : TOutputFormat = ofXML;
  359. const
  360. OSTarget: String = {$I %FPCTARGETOS%};
  361. CPUTarget: String = {$I %FPCTARGETCPU%};
  362. FPCVersion: String = {$I %FPCVERSION%};
  363. FPCDate: String = {$I %FPCDATE%};
  364. function TClassTreeEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  365. AParent: TPasElement; AVisibility : TPasMemberVisibility;
  366. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  367. begin
  368. Result := AClass.Create(AName, AParent);
  369. Result.Visibility:=AVisibility;
  370. if AClass.InheritsFrom(TPasModule) then
  371. CurModule := TPasModule(Result);
  372. If AClass.InheritsFrom(TPasClassType) then
  373. begin
  374. FObjects.AddObject(AName,Result);
  375. // Writeln('Added : ',AName);
  376. end;
  377. end;
  378. Constructor TClassTreeEngine.Create(AClassTree : TXMLDocument; AObjectKind : TPasObjKind);
  379. begin
  380. FPackage:=TPasPackage.Create('dummy',Nil);
  381. FTree:=TClassTreeBuilder.Create(FPackage,AObjectKind);
  382. FObjects:=TStringList.Create;
  383. Inherited Create;
  384. end;
  385. destructor TClassTreeEngine.Destroy;
  386. begin
  387. FreeAndNil(FTree);
  388. FreeAndNil(FPackage);
  389. FreeAndNil(FObjects);
  390. inherited Destroy;
  391. end;
  392. { ---------------------------------------------------------------------
  393. Main program. Document all units.
  394. ---------------------------------------------------------------------}
  395. Function MergeNodes(Doc : TXMLDocument;Dest,Source : TDomElement) : Integer;
  396. Var
  397. N : TDomNode;
  398. S,E : TDomElement;
  399. begin
  400. Result:=0;
  401. N:=Source.FirstChild;
  402. While (N<>Nil) do
  403. begin
  404. if (N.NodeType=ELEMENT_NODE) then
  405. begin
  406. S:=N as TDomElement;
  407. E:=Dest.FindNode(N.NodeName) as TDomElement;
  408. If (E=Nil) then
  409. begin
  410. E:=Doc.CreateElement(N.NodeName);
  411. If S['unit']<>'' then
  412. E['Unit']:=S['unit'];
  413. Dest.AppendChild(E);
  414. Inc(Result);
  415. end;
  416. Result:=Result+MergeNodes(Doc,E,S);
  417. end;
  418. N:=N.NextSibling;
  419. end;
  420. end;
  421. Function MergeTrees (Dest,Source : TXMLDocument) : Integer;
  422. Var
  423. S,D : TDomElement;
  424. begin
  425. Result:=0;
  426. D:=Dest.DocumentElement;
  427. S:=Source.DocumentElement;
  428. If (S.NodeName=D.NodeName) then
  429. Result:=MergeNodes(Dest,D,S)
  430. else
  431. Writeln(StdErr,Format(SSkipMerge,[S.NodeName,D.NodeName]));
  432. end;
  433. Function AnalyseFiles(Const AOutputName : String; InputFiles,MergeFiles : TStrings; AObjectKind : TPasObjKind) : String;
  434. Var
  435. XML,XML2 : TXMLDocument;
  436. I,ACount : Integer;
  437. Engine: TClassTreeEngine;
  438. begin
  439. Result:='';
  440. ACount:=0;
  441. XML:=TXMLDocument.Create;
  442. Try
  443. //XML.
  444. XML.AppendChild(XML.CreateElement('TObject'));
  445. For I:=0 to MergeFiles.Count-1 do
  446. begin
  447. XMl2:=TXMLDocument.Create;
  448. ReadXMLFile(XML2,MergeFiles[i]);
  449. try
  450. ACount:=ACount+MergeTrees(XML,XML2);
  451. WriteLn(StdErr,Format(SMergedFile,[ACount,MergeFiles[i]]));
  452. Finally
  453. FreeAndNil(XML2);
  454. end;
  455. end;
  456. For I:=0 to InputFiles.Count-1 do
  457. begin
  458. Engine := TClassTreeEngine.Create(XML,AObjectKind);
  459. Try
  460. ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget);
  461. Engine.Ftree.BuildTree(Engine.FObjects);
  462. ACount:=ACount+MergeTrees(XML,Engine.FTree.ClassTree);
  463. Finally
  464. FreeAndNil(Engine);
  465. end;
  466. end;
  467. Case OutputFormat of
  468. ofXML :
  469. WriteXMlFile(XML,AOutputName);
  470. ofPostScript :
  471. With TPostScriptClassChartFormatter.Create(XML) do
  472. try
  473. FileName:=AOutputName;
  474. CreateChart;
  475. finally
  476. Free;
  477. end;
  478. ofGraphViz :
  479. With TGraphVizClassChartFormatter.Create(XML) do
  480. try
  481. FileName:=AOutputName;
  482. CreateChart;
  483. finally
  484. Free;
  485. end;
  486. end;
  487. Writeln(StdErr,Format(SClassesAdded,[ACount,InputFiles.Count]));
  488. Finally
  489. XML.Free;
  490. end;
  491. end;
  492. { ---------------------------------------------------------------------
  493. Option management
  494. ---------------------------------------------------------------------}
  495. var
  496. cmdObjectKind : TPasObjKind;
  497. InputFiles,
  498. MergeFiles : TStringList;
  499. DocLang : String;
  500. OutputName: String;
  501. procedure InitOptions;
  502. begin
  503. InputFiles := TStringList.Create;
  504. MergeFiles := TStringList.Create;
  505. end;
  506. procedure FreeOptions;
  507. begin
  508. MergeFiles.Free;
  509. InputFiles.Free;
  510. end;
  511. { ---------------------------------------------------------------------
  512. Usage
  513. ---------------------------------------------------------------------}
  514. Procedure Usage;
  515. begin
  516. Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
  517. Writeln('Where [options] is one or more of :');
  518. Writeln(' --merge=filename Filename with object tree to merge.');
  519. Writeln(' --help Emit help.');
  520. Writeln(' --input=cmdline Input file to create skeleton for.');
  521. Writeln(' Use options are as for compiler.');
  522. Writeln(' --kind=objectkind Specify object kind. One of object, class, interface.');
  523. Writeln(' --lang=language Use selected language.');
  524. Writeln(' --output=filename Send output to file.');
  525. Writeln(' --format=name Kind of output to create: XML, PostScript, GraphViz.');
  526. end;
  527. procedure ParseOption(const s: String);
  528. procedure AddToFileList(List: TStringList; const FileName: String);
  529. var
  530. f: Text;
  531. s: String;
  532. begin
  533. if Copy(FileName, 1, 1) = '@' then
  534. begin
  535. Assign(f, Copy(FileName, 2, Length(FileName)));
  536. Reset(f);
  537. while not EOF(f) do
  538. begin
  539. ReadLn(f, s);
  540. List.Add(s);
  541. end;
  542. Close(f);
  543. end else
  544. List.Add(FileName);
  545. end;
  546. var
  547. i: Integer;
  548. Cmd, Arg: String;
  549. begin
  550. cmdObjectKind:=okClass;
  551. if (s = '-h') or (s = '--help') then
  552. begin
  553. Usage;
  554. Halt(0);
  555. end;
  556. i := Pos('=', s);
  557. if i > 0 then
  558. begin
  559. Cmd := Copy(s, 1, i - 1);
  560. Arg := Copy(s, i + 1, Length(s));
  561. end else
  562. begin
  563. Cmd := s;
  564. SetLength(Arg, 0);
  565. end;
  566. if (Cmd = '-i') or (Cmd = '--input') then
  567. AddToFileList(InputFiles, Arg)
  568. else if (Cmd = '-l') or (Cmd = '--lang') then
  569. DocLang := Arg
  570. else if (Cmd = '-o') or (Cmd = '--output') then
  571. OutputName := Arg
  572. else if (Cmd = '-k') or (Cmd = '--kind') then
  573. cmdObjectKind:=TPasObjKind(GetEnumValue(TypeInfo(TPasObjKind),'ok'+Arg))
  574. else if (Cmd = '-f') or (Cmd = '--format') then
  575. OutputFormat:=TOutputFormat(GetEnumValue(TypeInfo(TOutputFormat),'of'+Arg))
  576. else if Cmd = '--merge' then
  577. begin
  578. if FileExists(Arg) then
  579. MergeFiles.Add(Arg)
  580. else
  581. Writeln(StdErr,Format(SErrNoSuchMergeFile,[arg]));
  582. end
  583. else
  584. begin
  585. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  586. Usage;
  587. Halt(1);
  588. end;
  589. end;
  590. Function ParseCommandLine : Integer;
  591. Const
  592. {$IFDEF Unix}
  593. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  594. {$ELSE}
  595. MoFileTemplate ='intl/makeskel.%s.mo';
  596. {$ENDIF}
  597. var
  598. MOFilename: string;
  599. i: Integer;
  600. begin
  601. Result:=0;
  602. if ParamCount=0 then
  603. begin
  604. Usage;
  605. Halt(0);
  606. end;
  607. DocLang:='';
  608. for i := 1 to ParamCount do
  609. ParseOption(ParamStr(i));
  610. If (DocLang<>'') then
  611. begin
  612. MOFilename:=Format(MOFileTemplate,[DocLang]);
  613. if FileExists(MOFilename) then
  614. gettext.TranslateResourceStrings(MoFileName)
  615. else
  616. writeln('NOTE: unable to find translation file ',MOFilename);
  617. // Translate internal documentation strings
  618. TranslateDocStrings(DocLang);
  619. end;
  620. end;
  621. { ---------------------------------------------------------------------
  622. Main Program
  623. ---------------------------------------------------------------------}
  624. Procedure Run;
  625. var
  626. E: Integer;
  627. begin
  628. WriteLn(STitle);
  629. WriteLn(Format(SVersion, [FPCVersion, FPCDate]));
  630. WriteLn(SCopyright);
  631. InitOptions;
  632. Try
  633. E:=ParseCommandLine;
  634. If E<>0 then
  635. Halt(E);
  636. WriteLn;
  637. AnalyseFiles(OutputName,InputFiles,MergeFiles,cmdObjectKind);
  638. WriteLn(StdErr,SDone);
  639. Finally
  640. FreeOptions;
  641. end;
  642. end;
  643. Begin
  644. Run;
  645. end.