fpclasschart.pp 18 KB

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