fpclasschart.pp 19 KB

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