fpclasschart.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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; AObjectKindSet : TPasObjKindSet);
  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; AObjectKindSet : TPasObjKindSet);
  379. begin
  380. Inherited Create;
  381. FPackage:=TPasPackage.Create('dummy',Nil);
  382. FTree:=TClassTreeBuilder.Create(Self,FPackage,AObjectKindSet);
  383. FObjects:=TStringList.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 MergeTrees (Dest : TXMLDocument; aRootNode : TPasElementNode) : Integer;
  434. Var
  435. aSrc : TXMLDocument;
  436. Procedure AppendChildClasses(aParent : TDomElement; aNode : TPasElementNode);
  437. Var
  438. El : TDomElement;
  439. aChild : TPasElementNode;
  440. I : Integer;
  441. M : TPasModule;
  442. begin
  443. If (ANode=Nil) or (aNode.ChildCount=0) then exit;
  444. for I:=0 to aNode.ChildCount-1 do
  445. begin
  446. aChild:=aNode.Children[I];
  447. El:=aSrc.CreateElement(UTF8Decode(aChild.Element.Name));
  448. M:=aChild.Element.GetModule;
  449. If M<>Nil then
  450. EL['unit']:=UTF8Decode(M.Name);
  451. aParent.AppendChild(El);
  452. AppendChildClasses(El,aChild);
  453. end;
  454. end;
  455. begin
  456. Result:= 0;
  457. aSrc:=TXMLDocument.Create();
  458. try
  459. aSrc.AppendChild(aSrc.CreateElement('TObject'));
  460. AppendChildClasses(aSrc.DocumentElement,aRootNode);
  461. MergeTrees(Dest,aSrc);
  462. Inc(Result);
  463. finally
  464. aSrc.Free;
  465. end;
  466. end;
  467. Function AnalyseFiles(Const AOutputName : String; InputFiles,MergeFiles : TStrings; AObjectKind : TPasObjKind) : String;
  468. Var
  469. XML,XML2 : TXMLDocument;
  470. I,ACount : Integer;
  471. Engine: TClassTreeEngine;
  472. begin
  473. Result:='';
  474. ACount:=0;
  475. XML:=TXMLDocument.Create;
  476. Try
  477. //XML.
  478. XML.AppendChild(XML.CreateElement('TObject'));
  479. For I:=0 to MergeFiles.Count-1 do
  480. begin
  481. XMl2:=TXMLDocument.Create;
  482. ReadXMLFile(XML2,MergeFiles[i]);
  483. try
  484. ACount:=ACount+MergeTrees(XML,XML2);
  485. WriteLn(StdErr,Format(SMergedFile,[ACount,MergeFiles[i]]));
  486. Finally
  487. FreeAndNil(XML2);
  488. end;
  489. end;
  490. For I:=0 to InputFiles.Count-1 do
  491. begin
  492. Engine := TClassTreeEngine.Create(XML,[AObjectKind]);
  493. Try
  494. ParseSource(Engine,InputFiles[I],OSTarget,CPUTarget);
  495. Engine.Ftree.BuildTree(Engine.FObjects);
  496. ACount:=ACount+MergeTrees(XML,Engine.FTree.RootNode);
  497. Finally
  498. FreeAndNil(Engine);
  499. end;
  500. end;
  501. Case OutputFormat of
  502. ofXML :
  503. WriteXMlFile(XML,AOutputName);
  504. ofPostScript :
  505. With TPostScriptClassChartFormatter.Create(XML) do
  506. try
  507. FileName:=AOutputName;
  508. CreateChart;
  509. finally
  510. Free;
  511. end;
  512. ofGraphViz :
  513. With TGraphVizClassChartFormatter.Create(XML) do
  514. try
  515. FileName:=AOutputName;
  516. CreateChart;
  517. finally
  518. Free;
  519. end;
  520. end;
  521. Writeln(StdErr,Format(SClassesAdded,[ACount,InputFiles.Count]));
  522. Finally
  523. XML.Free;
  524. end;
  525. end;
  526. { ---------------------------------------------------------------------
  527. Option management
  528. ---------------------------------------------------------------------}
  529. var
  530. cmdObjectKind : TPasObjKind;
  531. InputFiles,
  532. MergeFiles : TStringList;
  533. DocLang : String;
  534. OutputName: String;
  535. procedure InitOptions;
  536. begin
  537. InputFiles := TStringList.Create;
  538. MergeFiles := TStringList.Create;
  539. end;
  540. procedure FreeOptions;
  541. begin
  542. MergeFiles.Free;
  543. InputFiles.Free;
  544. end;
  545. { ---------------------------------------------------------------------
  546. Usage
  547. ---------------------------------------------------------------------}
  548. Procedure Usage;
  549. begin
  550. Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
  551. Writeln('Where [options] is one or more of :');
  552. Writeln(' --merge=filename Filename with object tree to merge.');
  553. Writeln(' --help Emit help.');
  554. Writeln(' --input=cmdline Input file to create skeleton for.');
  555. Writeln(' Use options are as for compiler.');
  556. Writeln(' --kind=objectkind Specify object kind. One of object, class, interface.');
  557. Writeln(' --lang=language Use selected language.');
  558. Writeln(' --output=filename Send output to file.');
  559. Writeln(' --format=name Kind of output to create: XML, PostScript, GraphViz.');
  560. end;
  561. procedure ParseOption(const s: String);
  562. procedure AddToFileList(List: TStringList; const FileName: String);
  563. var
  564. f: Text;
  565. s: String;
  566. begin
  567. if Copy(FileName, 1, 1) = '@' then
  568. begin
  569. Assign(f, Copy(FileName, 2, Length(FileName)));
  570. Reset(f);
  571. while not EOF(f) do
  572. begin
  573. ReadLn(f, s);
  574. List.Add(s);
  575. end;
  576. Close(f);
  577. end else
  578. List.Add(FileName);
  579. end;
  580. var
  581. i: Integer;
  582. Cmd, Arg: String;
  583. begin
  584. cmdObjectKind:=okClass;
  585. if (s = '-h') or (s = '--help') then
  586. begin
  587. Usage;
  588. Halt(0);
  589. end;
  590. i := Pos('=', s);
  591. if i > 0 then
  592. begin
  593. Cmd := Copy(s, 1, i - 1);
  594. Arg := Copy(s, i + 1, Length(s));
  595. end else
  596. begin
  597. Cmd := s;
  598. SetLength(Arg, 0);
  599. end;
  600. if (Cmd = '-i') or (Cmd = '--input') then
  601. AddToFileList(InputFiles, Arg)
  602. else if (Cmd = '-l') or (Cmd = '--lang') then
  603. DocLang := Arg
  604. else if (Cmd = '-o') or (Cmd = '--output') then
  605. OutputName := Arg
  606. else if (Cmd = '-k') or (Cmd = '--kind') then
  607. cmdObjectKind:=TPasObjKind(GetEnumValue(TypeInfo(TPasObjKind),'ok'+Arg))
  608. else if (Cmd = '-f') or (Cmd = '--format') then
  609. OutputFormat:=TOutputFormat(GetEnumValue(TypeInfo(TOutputFormat),'of'+Arg))
  610. else if Cmd = '--merge' then
  611. begin
  612. if FileExists(Arg) then
  613. MergeFiles.Add(Arg)
  614. else
  615. Writeln(StdErr,Format(SErrNoSuchMergeFile,[arg]));
  616. end
  617. else
  618. begin
  619. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  620. Usage;
  621. Halt(1);
  622. end;
  623. end;
  624. Function ParseCommandLine : Integer;
  625. Const
  626. {$IFDEF Unix}
  627. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  628. {$ELSE}
  629. MoFileTemplate ='intl/makeskel.%s.mo';
  630. {$ENDIF}
  631. var
  632. MOFilename: string;
  633. i: Integer;
  634. begin
  635. Result:=0;
  636. if ParamCount=0 then
  637. begin
  638. Usage;
  639. Halt(0);
  640. end;
  641. DocLang:='';
  642. for i := 1 to ParamCount do
  643. ParseOption(ParamStr(i));
  644. If (DocLang<>'') then
  645. begin
  646. MOFilename:=Format(MOFileTemplate,[DocLang]);
  647. if FileExists(MOFilename) then
  648. gettext.TranslateResourceStrings(MoFileName)
  649. else
  650. writeln('NOTE: unable to find translation file ',MOFilename);
  651. // Translate internal documentation strings
  652. TranslateDocStrings(DocLang);
  653. end;
  654. end;
  655. { ---------------------------------------------------------------------
  656. Main Program
  657. ---------------------------------------------------------------------}
  658. Procedure Run;
  659. var
  660. E: Integer;
  661. begin
  662. WriteLn(STitle);
  663. WriteLn(Format(SVersion, [FPCVersion, FPCDate]));
  664. WriteLn(SCopyright);
  665. InitOptions;
  666. Try
  667. E:=ParseCommandLine;
  668. If E<>0 then
  669. Halt(E);
  670. WriteLn;
  671. AnalyseFiles(OutputName,InputFiles,MergeFiles,cmdObjectKind);
  672. WriteLn(StdErr,SDone);
  673. Finally
  674. FreeOptions;
  675. end;
  676. end;
  677. Begin
  678. Run;
  679. end.