dglobals.pp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. {
  2. $Id$
  3. FPDoc - Free Pascal Documentation Tool
  4. Copyright (C) 2000 - 2002 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. * Global declarations
  7. * Link list management
  8. * Document node tree
  9. * Main engine
  10. See the file COPYING, included in this distribution,
  11. for details about the copyright.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. }
  16. unit dGlobals;
  17. {$MODE objfpc}
  18. {$H+}
  19. interface
  20. uses Classes, DOM, PasTree, PParser;
  21. resourcestring
  22. // Output strings
  23. SDocPackageTitle = 'Reference for package ''%s''';
  24. SDocPrograms = 'Programs';
  25. SDocUnits = 'Units';
  26. SDocUnitTitle = 'Reference for unit ''%s''';
  27. SDocInterfaceSection = 'Interface section';
  28. SDocImplementationSection = 'Implementation section';
  29. SDocUsedUnits = 'Used units';
  30. SDocUsedUnitsByUnitXY = 'Used units by unit ''%s''';
  31. SDocConstsTypesVars = 'Constants, types and variables';
  32. SDocResStrings = 'Resource strings';
  33. SDocTypes = 'Types';
  34. SDocConstants = 'Constants';
  35. SDocClasses = 'Classes';
  36. SDocProceduresAndFunctions = 'Procedures and functions';
  37. SDocVariables = 'Variables';
  38. SDocUnitOverview = 'Overview of unit ''%s''';
  39. SDocOverview = 'Overview';
  40. SDocSearch = 'Search';
  41. SDocDeclaration = 'Declaration';
  42. SDocDescription = 'Description';
  43. SDocErrors = 'Errors';
  44. SDocSeeAlso = 'See also';
  45. SDocExample = 'Example';
  46. SDocArguments = 'Arguments';
  47. SDocFunctionResult = 'Function result';
  48. SDocRemark = 'Remark: ';
  49. SDocMethodOverview = 'Method overview';
  50. SDocPropertyOverview = 'Property overview';
  51. SDocPage = 'Page';
  52. SDocMethod = 'Method';
  53. SDocProperty = 'Property';
  54. SDocAccess = 'Access';
  55. SDocInheritance = 'Inheritance';
  56. SDocProperties = 'Properties';
  57. SDocMethods = 'Methods';
  58. SDocEvents = 'Events';
  59. SDocByName = 'by Name';
  60. SDocValue = 'Value';
  61. SDocExplanation = 'Explanation';
  62. SDocValuesForEnum = 'Enumeration values for type %s';
  63. type
  64. // Assumes a list of TObject instances and frees them on destruction
  65. TObjectList = class(TList)
  66. public
  67. destructor Destroy; override;
  68. end;
  69. { Link entry tree
  70. TFPDocEngine stores the root of the entry tree in its property
  71. "RootLinkNode". The root has one child node for each package, for which
  72. documentation links are available. The children of a package node
  73. are module nodes; and the children of a module node are the top-level
  74. declarations of this module; the next level in the tree stores e.g. record
  75. members, and so on...
  76. }
  77. TLinkNode = class
  78. private
  79. FFirstChild, FNextSibling: TLinkNode;
  80. FName: String;
  81. FLink: String;
  82. public
  83. constructor Create(const AName, ALink: String);
  84. destructor Destroy; override;
  85. function FindChild(const APathName: String): TLinkNode;
  86. function CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  87. // Properties for tree structure
  88. property FirstChild: TLinkNode read FFirstChild;
  89. property NextSibling: TLinkNode read FNextSibling;
  90. // Link properties
  91. property Name: String read FName;
  92. property Link: String read FLink;
  93. end;
  94. { Documentation entry tree
  95. TFPDocEngine stores the root of the entry tree in its property
  96. "RootDocNode". The root has one child node for each package, for which
  97. documentation is being provided by the user. The children of a package node
  98. are module nodes; and the children of a module node are the top-level
  99. declarations of this module; the next level in the tree stores e.g. record
  100. members, and so on...
  101. }
  102. TDocNode = class
  103. private
  104. FFirstChild, FNextSibling: TDocNode;
  105. FName: String;
  106. FNode: TDOMElement;
  107. FIsSkipped: Boolean;
  108. FShortDescr: TDOMElement;
  109. FDescr: TDOMElement;
  110. FErrorsDoc: TDOMElement;
  111. FSeeAlso: TDOMElement;
  112. FFirstExample: TDOMElement;
  113. FLink: String;
  114. public
  115. constructor Create(const AName: String; ANode: TDOMElement);
  116. destructor Destroy; override;
  117. function FindChild(const APathName: String): TDocNode;
  118. function CreateChildren(const APathName: String): TDocNode;
  119. // Properties for tree structure
  120. property FirstChild: TDocNode read FFirstChild;
  121. property NextSibling: TDocNode read FNextSibling;
  122. // Basic properties
  123. property Name: String read FName;
  124. property Node: TDOMElement read FNode;
  125. // Data fetched from the XML document
  126. property IsSkipped: Boolean read FIsSkipped;
  127. property ShortDescr: TDOMElement read FShortDescr;
  128. property Descr: TDOMElement read FDescr;
  129. property ErrorsDoc: TDOMElement read FErrorsDoc;
  130. property SeeAlso: TDOMElement read FSeeAlso;
  131. property FirstExample: TDOMElement read FFirstExample;
  132. property Link: String read FLink;
  133. end;
  134. // The main FPDoc engine
  135. TFPDocEngine = class(TPasTreeContainer)
  136. protected
  137. DescrDocs: TObjectList; // List of XML documents
  138. DescrDocNames: TStringList; // Names of the XML documents
  139. FRootLinkNode: TLinkNode;
  140. FRootDocNode: TDocNode;
  141. FPackages: TList; // List of TFPPackage objects
  142. CurModule: TPasModule;
  143. CurPackageDocNode: TDocNode;
  144. public
  145. constructor Create;
  146. destructor Destroy; override;
  147. procedure SetPackageName(const APackageName: String);
  148. procedure ReadContentFile(const AFilename, ALinkPrefix: String);
  149. procedure WriteContentFile(const AFilename: String);
  150. function CreateElement(AClass: TPTreeElement; const AName: String;
  151. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  152. override;
  153. function FindElement(const AName: String): TPasElement; override;
  154. function FindModule(const AName: String): TPasModule; override;
  155. // Link tree support
  156. procedure AddLink(const APathName, ALinkTo: String);
  157. function FindAbsoluteLink(const AName: String): String;
  158. function ResolveLink(AModule: TPasModule; const ALinkDest: String): String;
  159. // Documentation file support
  160. procedure AddDocFile(const AFilename: String);
  161. // Documentation retrieval
  162. function FindDocNode(AElement: TPasElement): TDocNode;
  163. function FindDocNode(ARefModule: TPasModule; const AName: String): TDocNode;
  164. function FindShortDescr(AElement: TPasElement): TDOMElement;
  165. function FindShortDescr(ARefModule: TPasModule;
  166. const AName: String): TDOMElement;
  167. function GetExampleFilename(const ExElement: TDOMElement): String;
  168. property RootLinkNode: TLinkNode read FRootLinkNode;
  169. property RootDocNode: TDocNode read FRootDocNode;
  170. property Package: TPasPackage read FPackage;
  171. Output: String;
  172. HasContentFile: Boolean;
  173. HidePrivate: Boolean; // Hide private class members in output?
  174. HideProtected: Boolean; // Hide protected class members in output?
  175. end;
  176. procedure TranslateDocStrings(const Lang: String);
  177. implementation
  178. uses SysUtils, Gettext, XMLRead;
  179. { TObjectList }
  180. destructor TObjectList.Destroy;
  181. var
  182. i: Integer;
  183. begin
  184. for i := 0 to Count - 1 do
  185. TObject(Items[i]).Free;
  186. inherited Destroy;
  187. end;
  188. { TLinkNode }
  189. constructor TLinkNode.Create(const AName, ALink: String);
  190. begin
  191. inherited Create;
  192. FName := AName;
  193. FLink := ALink;
  194. end;
  195. destructor TLinkNode.Destroy;
  196. begin
  197. if Assigned(FirstChild) then
  198. FirstChild.Free;
  199. if Assigned(NextSibling) then
  200. NextSibling.Free;
  201. inherited Destroy;
  202. end;
  203. function TLinkNode.FindChild(const APathName: String): TLinkNode;
  204. var
  205. DotPos: Integer;
  206. ChildName: String;
  207. Child: TLinkNode;
  208. begin
  209. if Length(APathName) = 0 then
  210. Result := Self
  211. else
  212. begin
  213. DotPos := Pos('.', APathName);
  214. if DotPos = 0 then
  215. ChildName := APathName
  216. else
  217. ChildName := Copy(APathName, 1, DotPos - 1);
  218. Child := FirstChild;
  219. while Assigned(Child) do
  220. begin
  221. if CompareText(Child.Name, ChildName) = 0 then
  222. begin
  223. if DotPos = 0 then
  224. Result := Child
  225. else
  226. Result := Child.FindChild(
  227. Copy(APathName, DotPos + 1, Length(APathName)));
  228. exit;
  229. end;
  230. Child := Child.NextSibling;
  231. end;
  232. Result := nil;
  233. end;
  234. end;
  235. function TLinkNode.CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  236. var
  237. DotPos: Integer;
  238. ChildName: String;
  239. Child, LastChild: TLinkNode;
  240. begin
  241. if Length(APathName) = 0 then
  242. Result := Self
  243. else
  244. begin
  245. DotPos := Pos('.', APathName);
  246. if DotPos = 0 then
  247. ChildName := APathName
  248. else
  249. ChildName := Copy(APathName, 1, DotPos - 1);
  250. Child := FirstChild;
  251. LastChild := nil;
  252. while Assigned(Child) do
  253. begin
  254. if CompareText(Child.Name, ChildName) = 0 then
  255. begin
  256. if DotPos = 0 then
  257. Result := Child
  258. else
  259. Result := Child.CreateChildren(
  260. Copy(APathName, DotPos + 1, Length(APathName)), ALinkTo);
  261. exit;
  262. end;
  263. LastChild := Child;
  264. Child := Child.NextSibling;
  265. end;
  266. { No child found, let's create one if we are at the end of the path }
  267. if DotPos > 0 then
  268. // !!!: better throw an exception
  269. WriteLn('Link path does not exist: ', APathName);
  270. Result := TLinkNode.Create(ChildName, ALinkTo);
  271. if Assigned(LastChild) then
  272. LastChild.FNextSibling := Result
  273. else
  274. FFirstChild := Result;
  275. end;
  276. end;
  277. { TDocNode }
  278. constructor TDocNode.Create(const AName: String; ANode: TDOMElement);
  279. begin
  280. inherited Create;
  281. FName := AName;
  282. FNode := ANode;
  283. end;
  284. destructor TDocNode.Destroy;
  285. begin
  286. if Assigned(FirstChild) then
  287. FirstChild.Free;
  288. if Assigned(NextSibling) then
  289. NextSibling.Free;
  290. inherited Destroy;
  291. end;
  292. function TDocNode.FindChild(const APathName: String): TDocNode;
  293. var
  294. DotPos: Integer;
  295. ChildName: String;
  296. Child: TDocNode;
  297. begin
  298. if Length(APathName) = 0 then
  299. Result := Self
  300. else
  301. begin
  302. DotPos := Pos('.', APathName);
  303. if DotPos = 0 then
  304. ChildName := APathName
  305. else
  306. ChildName := Copy(APathName, 1, DotPos - 1);
  307. Child := FirstChild;
  308. while Assigned(Child) do
  309. begin
  310. if CompareText(Child.Name, ChildName) = 0 then
  311. begin
  312. if DotPos = 0 then
  313. Result := Child
  314. else
  315. Result := Child.FindChild(
  316. Copy(APathName, DotPos + 1, Length(APathName)));
  317. exit;
  318. end;
  319. Child := Child.NextSibling;
  320. end;
  321. Result := nil;
  322. end;
  323. end;
  324. function TDocNode.CreateChildren(const APathName: String): TDocNode;
  325. var
  326. DotPos: Integer;
  327. ChildName: String;
  328. Child: TDocNode;
  329. begin
  330. if Length(APathName) = 0 then
  331. Result := Self
  332. else
  333. begin
  334. DotPos := Pos('.', APathName);
  335. if DotPos = 0 then
  336. ChildName := APathName
  337. else
  338. ChildName := Copy(APathName, 1, DotPos - 1);
  339. Child := FirstChild;
  340. while Assigned(Child) do
  341. begin
  342. if CompareText(Child.Name, ChildName) = 0 then
  343. begin
  344. if DotPos = 0 then
  345. Result := Child
  346. else
  347. Result := Child.CreateChildren(
  348. Copy(APathName, DotPos + 1, Length(APathName)));
  349. exit;
  350. end;
  351. Child := Child.NextSibling;
  352. end;
  353. // No child found, let's create one
  354. Result := TDocNode.Create(ChildName, nil);
  355. if Assigned(FirstChild) then
  356. begin
  357. Result.FNextSibling := FirstChild;
  358. FFirstChild := Result;
  359. end else
  360. FFirstChild := Result;
  361. if DotPos > 0 then
  362. Result := Result.CreateChildren(
  363. Copy(APathName, DotPos + 1, Length(APathName)));
  364. end;
  365. end;
  366. { TFPDocEngine }
  367. constructor TFPDocEngine.Create;
  368. begin
  369. inherited Create;
  370. DescrDocs := TObjectList.Create;
  371. DescrDocNames := TStringList.Create;
  372. FRootLinkNode := TLinkNode.Create('', '');
  373. FRootDocNode := TDocNode.Create('', nil);
  374. HidePrivate := True;
  375. FPackages := TList.Create;
  376. end;
  377. destructor TFPDocEngine.Destroy;
  378. var
  379. i: Integer;
  380. begin
  381. for i := 0 to FPackages.Count - 1 do
  382. TPasPackage(FPackages[i]).Release;
  383. FPackages.Free;
  384. FRootDocNode.Free;
  385. FRootLinkNode.Free;
  386. DescrDocNames.Free;
  387. DescrDocs.Free;
  388. inherited Destroy;
  389. end;
  390. procedure TFPDocEngine.SetPackageName(const APackageName: String);
  391. begin
  392. ASSERT(not Assigned(Package));
  393. FPackage := TPasPackage(inherited CreateElement(TPasPackage, '#' + APackageName, nil));
  394. FPackages.Add(FPackage);
  395. CurPackageDocNode := RootDocNode.FindChild('#' + APackageName);
  396. end;
  397. procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
  398. var
  399. f: Text;
  400. procedure ReadLinkTree;
  401. var
  402. s: String;
  403. PrevSpaces, ThisSpaces, i, StackIndex: Integer;
  404. CurParent, PrevSibling, NewNode: TLinkNode;
  405. ParentStack, SiblingStack: array[0..7] of TLinkNode;
  406. begin
  407. PrevSpaces := 0;
  408. CurParent := RootLinkNode;
  409. PrevSibling := nil;
  410. StackIndex := 0;
  411. while True do
  412. begin
  413. ReadLn(f, s);
  414. if Length(s) = 0 then
  415. break;
  416. ThisSpaces := 0;
  417. while s[ThisSpaces + 1] = ' ' do
  418. Inc(ThisSpaces);
  419. if ThisSpaces <> PrevSpaces then
  420. begin
  421. if ThisSpaces > PrevSpaces then
  422. begin
  423. { Dive down one level }
  424. ParentStack[StackIndex] := CurParent;
  425. SiblingStack[StackIndex] := PrevSibling;
  426. Inc(StackIndex);
  427. CurParent := PrevSibling;
  428. PrevSibling := nil;
  429. end else
  430. while PrevSpaces > ThisSpaces do
  431. begin
  432. Dec(StackIndex);
  433. CurParent := ParentStack[StackIndex];
  434. PrevSibling := SiblingStack[StackIndex];
  435. Dec(PrevSpaces);
  436. end;
  437. PrevSpaces := ThisSpaces;
  438. end;
  439. i := ThisSpaces + 1;
  440. while s[i] <> ' ' do
  441. Inc(i);
  442. NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
  443. ALinkPrefix + Copy(s, i + 1, Length(s)));
  444. if Assigned(PrevSibling) then
  445. PrevSibling.FNextSibling := NewNode
  446. else
  447. CurParent.FFirstChild := NewNode;
  448. PrevSibling := NewNode;
  449. end;
  450. end;
  451. procedure ReadClasses;
  452. function CreateClass(const AName: String): TPasClassType;
  453. var
  454. DotPos, DotPos2, i: Integer;
  455. s: String;
  456. Package: TPasPackage;
  457. Module: TPasModule;
  458. begin
  459. // Find or create package
  460. DotPos := Pos('.', AName);
  461. s := Copy(AName, 1, DotPos - 1);
  462. Package := nil;
  463. for i := 0 to FPackages.Count - 1 do
  464. if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
  465. begin
  466. Package := TPasPackage(FPackages[i]);
  467. break;
  468. end;
  469. if not Assigned(Package) then
  470. begin
  471. Package := TPasPackage(inherited CreateElement(TPasPackage, s, nil));
  472. FPackages.Add(Package);
  473. end;
  474. // Find or create module
  475. DotPos2 := DotPos;
  476. repeat
  477. Inc(DotPos2);
  478. until AName[DotPos2] = '.';
  479. s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
  480. Module := nil;
  481. for i := 0 to Package.Modules.Count - 1 do
  482. if CompareText(TPasModule(Package.Modules[i]).Name, s) = 0 then
  483. begin
  484. Module := TPasModule(Package.Modules[i]);
  485. break;
  486. end;
  487. if not Assigned(Module) then
  488. begin
  489. Module := TPasModule.Create(s, Package);
  490. Module.InterfaceSection := TPasSection.Create('', Module);
  491. Package.Modules.Add(Module);
  492. end;
  493. // Create node for class
  494. Result := TPasClassType.Create(Copy(AName, DotPos2 + 1, Length(AName)),
  495. Module.InterfaceSection);
  496. Result.ObjKind := okClass;
  497. Module.InterfaceSection.Declarations.Add(Result);
  498. Module.InterfaceSection.Classes.Add(Result);
  499. end;
  500. var
  501. s, Name: String;
  502. CurClass: TPasClassType;
  503. i: Integer;
  504. Member: TPasElement;
  505. begin
  506. CurClass := nil;
  507. while True do
  508. begin
  509. ReadLn(f, s);
  510. if Length(s) = 0 then
  511. break;
  512. if s[1] = '#' then
  513. begin
  514. // New class
  515. i := Pos(' ', s);
  516. CurClass := CreateClass(Copy(s, 1, i - 1));
  517. end else
  518. begin
  519. i := Pos(' ', s);
  520. if i = 0 then
  521. Name := Copy(s, 3, Length(s))
  522. else
  523. Name := Copy(s, 3, i - 3);
  524. case s[2] of
  525. 'M':
  526. Member := TPasProcedure.Create(Name, CurClass);
  527. 'P':
  528. begin
  529. Member := TPasProperty.Create(Name, CurClass);
  530. if i > 0 then
  531. while i <= Length(s) do
  532. begin
  533. case s[i] of
  534. 'r':
  535. TPasProperty(Member).ReadAccessorName := '<dummy>';
  536. 'w':
  537. TPasProperty(Member).WriteAccessorName := '<dummy>';
  538. 's':
  539. TPasProperty(Member).StoredAccessorName := '<dummy>';
  540. end;
  541. Inc(i);
  542. end;
  543. end;
  544. 'V':
  545. Member := TPasVariable.Create(Name, CurClass);
  546. else
  547. raise Exception.Create('Invalid member type: ' + s[2]);
  548. end;
  549. CurClass.Members.Add(Member);
  550. end;
  551. end;
  552. end;
  553. var
  554. s: String;
  555. begin
  556. Assign(f, AFilename);
  557. Reset(f);
  558. while not EOF(f) do
  559. begin
  560. ReadLn(f, s);
  561. if (Length(s) = 0) or (s[1] = '#') then
  562. continue;
  563. if s = ':link tree' then
  564. ReadLinkTree
  565. else if s = ':classes' then
  566. ReadClasses
  567. else
  568. repeat
  569. ReadLn(f, s);
  570. until EOF(f) or (Length(s) = 0);
  571. end;
  572. Close(f);
  573. end;
  574. procedure TFPDocEngine.WriteContentFile(const AFilename: String);
  575. var
  576. ContentFile: Text;
  577. procedure ProcessLinkNode(ALinkNode: TLinkNode; const AIdent: String);
  578. var
  579. ChildNode: TLinkNode;
  580. begin
  581. WriteLn(ContentFile, AIdent, ALinkNode.Name, ' ', ALinkNode.Link);
  582. ChildNode := ALinkNode.FirstChild;
  583. while Assigned(ChildNode) do
  584. begin
  585. ProcessLinkNode(ChildNode, AIdent + ' ');
  586. ChildNode := ChildNode.NextSibling;
  587. end;
  588. end;
  589. var
  590. LinkNode: TLinkNode;
  591. i, j, k: Integer;
  592. Module: TPasModule;
  593. ClassDecl: TPasClassType;
  594. Member: TPasElement;
  595. s: String;
  596. begin
  597. Assign(ContentFile, AFilename);
  598. Rewrite(ContentFile);
  599. try
  600. WriteLn(ContentFile, '# FPDoc Content File');
  601. WriteLn(ContentFile, ':link tree');
  602. LinkNode := RootLinkNode.FirstChild;
  603. while Assigned(LinkNode) do
  604. begin
  605. if LinkNode.Name = Package.Name then
  606. begin
  607. ProcessLinkNode(LinkNode, '');
  608. end;
  609. LinkNode := LinkNode.NextSibling;
  610. end;
  611. if Assigned(Package) then
  612. begin
  613. WriteLn(ContentFile);
  614. WriteLn(ContentFile, ':classes');
  615. for i := 0 to Package.Modules.Count - 1 do
  616. begin
  617. Module := TPasModule(Package.Modules[i]);
  618. for j := 0 to Module.InterfaceSection.Classes.Count - 1 do
  619. begin
  620. ClassDecl := TPasClassType(Module.InterfaceSection.Classes[j]);
  621. Write(ContentFile, ClassDecl.PathName, ' ');
  622. if Assigned(ClassDecl.AncestorType) then
  623. WriteLn(ContentFile, ClassDecl.AncestorType.PathName)
  624. else if ClassDecl.ObjKind = okClass then
  625. WriteLn(ContentFile, '.TObject');
  626. for k := 0 to ClassDecl.Members.Count - 1 do
  627. begin
  628. Member := TPasElement(ClassDecl.Members[k]);
  629. Write(ContentFile, Chr(Ord(Member.Visibility) + Ord('0')));
  630. SetLength(s, 0);
  631. if Member.ClassType = TPasVariable then
  632. Write(ContentFile, 'V')
  633. else if Member.ClassType = TPasProperty then
  634. begin
  635. Write(ContentFile, 'P');
  636. if Length(TPasProperty(Member).ReadAccessorName) > 0 then
  637. s := s + 'r';
  638. if Length(TPasProperty(Member).WriteAccessorName) > 0 then
  639. s := s + 'w';
  640. if Length(TPasProperty(Member).StoredAccessorName) > 0 then
  641. s := s + 's';
  642. end else
  643. Write(ContentFile, 'M'); // Member must be a method
  644. Write(ContentFile, Member.Name);
  645. if Length(s) > 0 then
  646. WriteLn(ContentFile, ' ', s)
  647. else
  648. WriteLn(ContentFile);
  649. end;
  650. end;
  651. end;
  652. end;
  653. finally
  654. Close(ContentFile);
  655. end;
  656. end;
  657. function TFPDocEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  658. AParent: TPasElement; AVisibility: TPasMemberVisibility): TPasElement;
  659. begin
  660. Result := AClass.Create(AName, AParent);
  661. Result.Visibility := AVisibility;
  662. if AClass.InheritsFrom(TPasModule) then
  663. CurModule := TPasModule(Result);
  664. end;
  665. function TFPDocEngine.FindElement(const AName: String): TPasElement;
  666. function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
  667. var
  668. l: TList;
  669. i: Integer;
  670. begin
  671. l := AModule.InterfaceSection.Declarations;
  672. for i := 0 to l.Count - 1 do
  673. begin
  674. Result := TPasElement(l[i]);
  675. if CompareText(Result.Name, LocalName) = 0 then
  676. exit;
  677. end;
  678. Result := nil;
  679. end;
  680. var
  681. i: Integer;
  682. //ModuleName, LocalName: String;
  683. Module: TPasElement;
  684. begin
  685. {!!!: Don't know if we ever will have to use the following:
  686. i := Pos('.', AName);
  687. if i <> 0 then
  688. begin
  689. WriteLn('Dot found in name: ', AName);
  690. Result := nil;
  691. end else
  692. begin}
  693. Result := FindInModule(CurModule, AName);
  694. if not Assigned(Result) then
  695. for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
  696. begin
  697. Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
  698. if Module.ClassType = TPasModule then
  699. begin
  700. Result := FindInModule(TPasModule(Module), AName);
  701. if Assigned(Result) then
  702. exit;
  703. end;
  704. end;
  705. {end;}
  706. end;
  707. function TFPDocEngine.FindModule(const AName: String): TPasModule;
  708. function FindInPackage(APackage: TPasPackage): TPasModule;
  709. var
  710. i: Integer;
  711. begin
  712. for i := 0 to APackage.Modules.Count - 1 do
  713. begin
  714. Result := TPasModule(APackage.Modules[i]);
  715. if CompareText(Result.Name, AName) = 0 then
  716. exit;
  717. end;
  718. Result := nil;
  719. end;
  720. var
  721. i: Integer;
  722. begin
  723. Result := FindInPackage(Package);
  724. if not Assigned(Result) then
  725. for i := FPackages.Count - 1 downto 0 do
  726. begin
  727. if TPasPackage(FPackages[i]) = Package then
  728. continue;
  729. Result := FindInPackage(TPasPackage(FPackages[i]));
  730. if Assigned(Result) then
  731. exit;
  732. end;
  733. end;
  734. procedure TFPDocEngine.AddLink(const APathName, ALinkTo: String);
  735. begin
  736. RootLinkNode.CreateChildren(APathName, ALinkTo);
  737. end;
  738. function TFPDocEngine.FindAbsoluteLink(const AName: String): String;
  739. var
  740. LinkNode: TLinkNode;
  741. begin
  742. LinkNode := RootLinkNode.FindChild(AName);
  743. if Assigned(LinkNode) then
  744. Result := LinkNode.Link
  745. else
  746. SetLength(Result, 0);
  747. end;
  748. function TFPDocEngine.ResolveLink(AModule: TPasModule;
  749. const ALinkDest: String): String;
  750. var
  751. i: Integer;
  752. ThisPackage: TLinkNode;
  753. UnitList: TList;
  754. begin
  755. //WriteLn('ResolveLink(', ALinkDest, ')... ');
  756. if Length(ALinkDest) = 0 then
  757. begin
  758. SetLength(Result, 0);
  759. exit;
  760. end;
  761. if ALinkDest[1] = '#' then
  762. Result := FindAbsoluteLink(ALinkDest)
  763. else
  764. begin
  765. Result := ResolveLink(AModule, AModule.PathName + '.' + ALinkDest);
  766. if Length(Result) > 0 then
  767. exit;
  768. { Try all packages }
  769. SetLength(Result, 0);
  770. ThisPackage := RootLinkNode.FirstChild;
  771. while Assigned(ThisPackage) do
  772. begin
  773. Result := ResolveLink(AModule, ThisPackage.Name + '.' + ALinkDest);
  774. if Length(Result) > 0 then
  775. exit;
  776. ThisPackage := ThisPackage.NextSibling;
  777. end;
  778. if Length(Result) = 0 then
  779. begin
  780. { Okay, then we have to try all imported units of the current module }
  781. UnitList := AModule.InterfaceSection.UsesList;
  782. for i := UnitList.Count - 1 downto 0 do
  783. begin
  784. { Try all packages }
  785. ThisPackage := RootLinkNode.FirstChild;
  786. while Assigned(ThisPackage) do
  787. begin
  788. Result := ResolveLink(AModule, ThisPackage.Name + '.' +
  789. TPasType(UnitList[i]).Name + '.' + ALinkDest);
  790. if Length(Result) > 0 then
  791. exit;
  792. ThisPackage := ThisPackage.NextSibling;
  793. end;
  794. end;
  795. end;
  796. end;
  797. if Length(Result) = 0 then
  798. for i := Length(ALinkDest) downto 1 do
  799. if ALinkDest[i] = '.' then
  800. begin
  801. Result := ResolveLink(AModule, Copy(ALinkDest, 1, i - 1));
  802. exit;
  803. end;
  804. end;
  805. procedure TFPDocEngine.AddDocFile(const AFilename: String);
  806. function ReadNode(OwnerDocNode: TDocNode; Element: TDOMElement): TDocNode;
  807. var
  808. Subnode: TDOMNode;
  809. begin
  810. if OwnerDocNode = RootDocNode then
  811. Result := OwnerDocNode.CreateChildren('#' + Element['name'])
  812. else
  813. Result := OwnerDocNode.CreateChildren(Element['name']);
  814. Result.FNode := Element;
  815. Result.FLink := Element['link'];
  816. Result.FIsSkipped := Element['skip'] = '1';
  817. Subnode := Element.FirstChild;
  818. while Assigned(Subnode) do
  819. begin
  820. if Subnode.NodeType = ELEMENT_NODE then
  821. begin
  822. if Subnode.NodeName = 'short' then
  823. Result.FShortDescr := TDOMElement(Subnode)
  824. else if Subnode.NodeName = 'descr' then
  825. Result.FDescr := TDOMElement(Subnode)
  826. else if Subnode.NodeName = 'errors' then
  827. Result.FErrorsDoc := TDOMElement(Subnode)
  828. else if Subnode.NodeName = 'seealso' then
  829. Result.FSeeAlso := TDOMElement(Subnode)
  830. else if (Subnode.NodeName = 'example') and
  831. not Assigned(Result.FirstExample) then
  832. Result.FFirstExample := TDOMElement(Subnode);
  833. end;
  834. Subnode := Subnode.NextSibling;
  835. end;
  836. end;
  837. var
  838. i: Integer;
  839. Node, Subnode, Subsubnode: TDOMNode;
  840. Element: TDOMElement;
  841. Doc: TXMLDocument;
  842. PackageDocNode, ModuleDocNode: TDocNode;
  843. begin
  844. ReadXMLFile(Doc, AFilename);
  845. DescrDocs.Add(Doc);
  846. DescrDocNames.Add(AFilename);
  847. Node := Doc.DocumentElement.FirstChild;
  848. while Assigned(Node) do
  849. begin
  850. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'package') then
  851. begin
  852. PackageDocNode := ReadNode(RootDocNode, TDOMElement(Node));
  853. // Scan all 'module' elements within this package element
  854. Subnode := Node.FirstChild;
  855. while Assigned(Subnode) do
  856. begin
  857. if (Subnode.NodeType = ELEMENT_NODE) and
  858. (Subnode.NodeName = 'module') then
  859. begin
  860. ModuleDocNode := ReadNode(PackageDocNode, TDOMElement(Subnode));
  861. // Scan all 'element' elements within this module element
  862. Subsubnode := Subnode.FirstChild;
  863. while Assigned(Subsubnode) do
  864. begin
  865. if (Subsubnode.NodeType = ELEMENT_NODE) and
  866. (Subsubnode.NodeName = 'element') then
  867. ReadNode(ModuleDocNode, TDOMElement(Subsubnode));
  868. Subsubnode := Subsubnode.NextSibling;
  869. end;
  870. end;
  871. Subnode := Subnode.NextSibling;
  872. end;
  873. end;
  874. Node := Node.NextSibling;
  875. end;
  876. end;
  877. function TFPDocEngine.FindDocNode(AElement: TPasElement): TDocNode;
  878. begin
  879. if AElement.InheritsFrom(TPasUnresolvedTypeRef) then
  880. Result := FindDocNode(AElement.GetModule, AElement.Name)
  881. else
  882. Result := RootDocNode.FindChild(AElement.PathName);
  883. end;
  884. function TFPDocEngine.FindDocNode(ARefModule: TPasModule;
  885. const AName: String): TDocNode;
  886. var
  887. CurPackage: TDocNode;
  888. UnitList: TList;
  889. i: Integer;
  890. begin
  891. if Length(AName) = 0 then
  892. Result := nil
  893. else
  894. begin
  895. if AName[1] = '#' then
  896. Result := RootDocNode.FindChild(AName)
  897. else
  898. Result := RootDocNode.FindChild(Package.Name + '.' + AName);
  899. if (not Assigned(Result)) and Assigned(ARefModule) then
  900. Result := RootDocNode.FindChild(ARefModule.PathName + '.' + AName);
  901. if (not Assigned(Result)) and (AName[1] <> '#') then
  902. begin
  903. CurPackage := RootDocNode.FirstChild;
  904. while Assigned(CurPackage) do
  905. begin
  906. Result := RootDocNode.FindChild(CurPackage.Name + '.' + AName);
  907. if Assigned(Result) then
  908. break;
  909. CurPackage := CurPackage.NextSibling;
  910. end;
  911. if not Assigned(Result) then
  912. begin
  913. { Okay, then we have to try all imported units of the current module }
  914. UnitList := CurModule.InterfaceSection.UsesList;
  915. for i := UnitList.Count - 1 downto 0 do
  916. begin
  917. { Try all packages }
  918. CurPackage := RootDocNode.FirstChild;
  919. while Assigned(CurPackage) do
  920. begin
  921. Result := RootDocNode.FindChild(CurPackage.Name + '.' +
  922. TPasType(UnitList[i]).Name + '.' + AName);
  923. if Assigned(Result) then
  924. break;
  925. CurPackage := CurPackage.NextSibling;
  926. end;
  927. end;
  928. end;
  929. end;
  930. end;
  931. end;
  932. function TFPDocEngine.FindShortDescr(AElement: TPasElement): TDOMElement;
  933. var
  934. DocNode: TDocNode;
  935. begin
  936. DocNode := FindDocNode(AElement);
  937. if Assigned(DocNode) then
  938. Result := DocNode.ShortDescr
  939. else
  940. Result := nil;
  941. end;
  942. function TFPDocEngine.FindShortDescr(ARefModule: TPasModule;
  943. const AName: String): TDOMElement;
  944. var
  945. DocNode: TDocNode;
  946. begin
  947. DocNode := FindDocNode(ARefModule, AName);
  948. if Assigned(DocNode) then
  949. Result := DocNode.ShortDescr
  950. else
  951. Result := nil;
  952. end;
  953. function TFPDocEngine.GetExampleFilename(const ExElement: TDOMElement): String;
  954. var
  955. i: Integer;
  956. begin
  957. for i := 0 to DescrDocs.Count - 1 do
  958. if TDOMDocument(DescrDocs[i]) = ExElement.OwnerDocument then
  959. begin
  960. Result := ExtractFilePath(DescrDocNames[i]) + ExElement['file'];
  961. exit;
  962. end;
  963. SetLength(Result, 0);
  964. end;
  965. { Global helpers }
  966. procedure TranslateDocStrings(const Lang: String);
  967. var
  968. mo: TMOFile;
  969. begin
  970. {$IFDEF Unix}
  971. mo := TMOFile.Create(Format('/usr/local/share/locale/%s/LC_MESSAGES/dglobals.mo', [Lang]));
  972. {$ELSE}
  973. mo := TMOFile.Create(Format('intl/dglobals.%s.mo', [Lang]));
  974. {$ENDIF}
  975. try
  976. TranslateResourceStrings(mo);
  977. finally
  978. mo.Free;
  979. end;
  980. end;
  981. end.
  982. {
  983. $Log$
  984. Revision 1.1 2003-03-17 23:03:20 michael
  985. + Initial import in CVS
  986. Revision 1.13 2003/03/13 22:02:13 sg
  987. * New version with many bugfixes and our own parser (now independent of the
  988. compiler source)
  989. Revision 1.12 2002/11/15 19:44:18 sg
  990. * Cosmetic changes
  991. Revision 1.11 2002/10/12 17:00:45 michael
  992. + Changes to be able to disable private/protected nodes in skeleton
  993. Revision 1.10 2002/05/24 00:13:22 sg
  994. * much improved new version, including many linking and output fixes
  995. Revision 1.9 2002/03/25 23:16:24 sg
  996. * fixed missing storing of documenation data for the DocNode of a module
  997. (so e.g. the Unit Overview is working again)
  998. Revision 1.8 2002/03/12 10:58:35 sg
  999. * reworked linking engine and internal structure
  1000. Revision 1.7 2002/01/20 11:19:55 michael
  1001. + Added link attribute and property to TFPelement
  1002. Revision 1.6 2001/12/17 22:16:02 sg
  1003. * Added TFPDocEngine.HideProtected
  1004. }