dglobals.pp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. {
  2. FPDoc - Free Pascal Documentation Tool
  3. Copyright (C) 2000 - 2002 by
  4. Areca Systems GmbH / Sebastian Guenther, [email protected]
  5. * Global declarations
  6. * Link list management
  7. * Document node tree
  8. * Main engine
  9. See the file COPYING, included in this distribution,
  10. for details about the copyright.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. }
  15. {$MODE objfpc}
  16. {$H+}
  17. unit dGlobals;
  18. interface
  19. uses Classes, DOM, PasTree, PParser;
  20. Var
  21. LEOL : Integer;
  22. modir : string;
  23. resourcestring
  24. // Output strings
  25. SDocPackageTitle = 'Reference for package ''%s''';
  26. SDocPrograms = 'Programs';
  27. SDocUnits = 'Units';
  28. SDocUnitTitle = 'Reference for unit ''%s''';
  29. SDocInterfaceSection = 'Interface section';
  30. SDocImplementationSection = 'Implementation section';
  31. SDocUsedUnits = 'Used units';
  32. SDocUsedUnitsByUnitXY = 'Used units by unit ''%s''';
  33. SDocConstsTypesVars = 'Constants, types and variables';
  34. SDocResStrings = 'Resource strings';
  35. SDocTypes = 'Types';
  36. SDocConstants = 'Constants';
  37. SDocClasses = 'Classes';
  38. SDocProceduresAndFunctions = 'Procedures and functions';
  39. SDocVariables = 'Variables';
  40. SDocIdentifierIndex = 'Index';
  41. SDocModuleIndex = 'Index of all identifiers in unit ''%s''';
  42. SDocPackageIndex = 'Index of all identifiers in package ''%s''';
  43. SDocUnitOverview = 'Overview of unit ''%s''';
  44. SDocOverview = 'Overview';
  45. SDocSearch = 'Search';
  46. SDocDeclaration = 'Declaration';
  47. SDocDescription = 'Description';
  48. SDocErrors = 'Errors';
  49. SDocSeeAlso = 'See also';
  50. SDocExample = 'Example';
  51. SDocArguments = 'Arguments';
  52. SDocFunctionResult = 'Function result';
  53. SDocRemark = 'Remark: ';
  54. SDocMethodOverview = 'Method overview';
  55. SDocPropertyOverview = 'Property overview';
  56. SDocPage = 'Page';
  57. SDocMethod = 'Method';
  58. SDocProperty = 'Property';
  59. SDocAccess = 'Access';
  60. SDocInheritance = 'Inheritance';
  61. SDocProperties = 'Properties';
  62. SDocMethods = 'Methods';
  63. SDocEvents = 'Events';
  64. SDocByName = 'by Name';
  65. SDocValue = 'Value';
  66. SDocExplanation = 'Explanation';
  67. SDocProcedure = 'Procedure';
  68. SDocValuesForEnum = 'Enumeration values for type %s';
  69. SDocSourcePosition = 'Source position: %s line %d';
  70. SDocSynopsis = 'Synopsis';
  71. SDocVisibility = 'Visibility';
  72. SDocOpaque = 'Opaque type';
  73. SDocDateGenerated = 'Documentation generated on: %s';
  74. // Topics
  75. SDocRelatedTopics = 'Related topics';
  76. SDocUp = 'Up';
  77. SDocNext = 'Next';
  78. SDocPrevious = 'Previous';
  79. // Various backend constants
  80. SDocChapter = 'Chapter';
  81. SDocSection = 'Section';
  82. SDocSubSection = 'Subsection';
  83. SDocTable = 'Table';
  84. SDocListing = 'Listing';
  85. // Man page usage
  86. SManUsageManSection = 'Use ASection as the man page section';
  87. SManUsageNoUnitPrefix = 'Do not prefix man pages with unit name.';
  88. SManUsageWriterDescr = 'UNIX man page output.';
  89. SManUsagePackageDescription = 'Use descr as the description of man pages';
  90. // HTML usage
  91. SHTMLUsageFooter = 'Append xhtml from file as footer to html page';
  92. SHTMLUsageFooterDate = 'Append footer with date. fmt is Optional format for FormatDateTime';
  93. SHTMLUsageCharset = 'Set the HTML character set';
  94. SHTMLHtmlSearch = 'Add search page with given name to the menu bar';
  95. SHTMLIndexColcount = 'Use N columns in the identifier index pages';
  96. SHTMLImageUrl = 'Prefix image URLs with url';
  97. // CHM usage
  98. SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.';
  99. SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.';
  100. SCHMUsageDefPage = 'Set the "Home" page relative to where it lives in the chm. i.e. "/index.html"';
  101. SCHMUsageOtrFiles= 'A txt file containing a list of files to be added relative to the working directory.';
  102. SCHMUsageCSSFile = 'Filename of a .css file to be included in the chm.';
  103. SCHMUsageAutoTOC = 'Automatically generate a Table of Contents. Ignores --toc-file';
  104. SCHMUsageAutoIDX = 'Automatically generate an Index. Ignores --index-file';
  105. SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*';
  106. STitle = 'FPDoc - Free Pascal Documentation Tool';
  107. SVersion = 'Version %s [%s]';
  108. SCopyright = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]';
  109. SCmdLineHelp = 'Usage: %s [options]';
  110. SUsageOption010 = '--content Create content file for package cross-references';
  111. SUsageOption020 = '--cputarget=value Set the target CPU for the scanner.';
  112. SUsageOption030 = '--descr=name use name as description file. ';
  113. SUsageOption040 = ' This option is allowed more than once';
  114. SUsageOption050 = '--format=fmt Select output format.';
  115. SUsageOption060 = '--help Show this help.';
  116. SUsageOption070 = '--hide-protected Do not show protected methods in overview';
  117. SUsageOption080 = '--import=file Import content file for package cross-references';
  118. SUsageOption090 = '--input=cmd use cmd as input for the parser.';
  119. SUsageOption100 = ' At least one input option is required.';
  120. SUsageOption110 = '--lang=lng Select output language.';
  121. SUsageOption120 = '--ostarget=value Set the target OS for the scanner.';
  122. SUsageOption130 = '--output=name use name as the output name.';
  123. SUsageOption140 = ' Each backend interpretes this as needed.';
  124. SUsageOption150 = '--package=name Set the package name for which to create output';
  125. SUsageOption160 = '--show-private Show private methods.';
  126. SUsageOption170 = '--warn-no-node Warn if no documentation node was found.';
  127. SUsageOption180 = '--mo-dir=dir Set directory where language files reside to dir';
  128. SUsageFormats = 'The following output formats are supported by this fpdoc:';
  129. SUsageBackendHelp = 'Specify an output format, combined with --help to get more help for this backend.';
  130. SUsageFormatSpecific = 'Output format "%s" supports the following options:';
  131. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  132. SCmdLineInvalidFormat = 'Invalid format "%s" specified';
  133. SCmdLineOutputOptionMissing = 'Need an output filename, please specify one with --output=<filename>';
  134. SWritingPages = 'Writing %d pages...';
  135. SNeedPackageName = 'No package name specified. Please specify one using the --package option.';
  136. SDone = 'Done.';
  137. SErrCouldNotCreateOutputDir = 'Could not create output directory "%s"';
  138. SErrCouldNotCreateFile = 'Could not create file "%s": %s';
  139. SSeeURL = '(See %s)'; // For lineair text writers.
  140. Const
  141. SVisibility: array[TPasMemberVisibility] of string =
  142. ('Default', 'Private', 'Protected', 'Public',
  143. 'Published', 'Automated');
  144. type
  145. // Assumes a list of TObject instances and frees them on destruction
  146. TObjectList = class(TList)
  147. public
  148. destructor Destroy; override;
  149. end;
  150. { Link entry tree
  151. TFPDocEngine stores the root of the entry tree in its property
  152. "RootLinkNode". The root has one child node for each package, for which
  153. documentation links are available. The children of a package node
  154. are module nodes; and the children of a module node are the top-level
  155. declarations of this module; the next level in the tree stores e.g. record
  156. members, and so on...
  157. }
  158. TLinkNode = class
  159. private
  160. FFirstChild, FNextSibling: TLinkNode;
  161. FName: String;
  162. FLink: String;
  163. public
  164. constructor Create(const AName, ALink: String);
  165. destructor Destroy; override;
  166. function FindChild(const APathName: String): TLinkNode;
  167. function CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  168. // Properties for tree structure
  169. property FirstChild: TLinkNode read FFirstChild;
  170. property NextSibling: TLinkNode read FNextSibling;
  171. // Link properties
  172. property Name: String read FName;
  173. property Link: String read FLink;
  174. end;
  175. { Documentation entry tree
  176. TFPDocEngine stores the root of the entry tree in its property
  177. "RootDocNode". The root has one child node for each package, for which
  178. documentation is being provided by the user. The children of a package node
  179. are module nodes; and the children of a module node are the top-level
  180. declarations of this module; the next level in the tree stores e.g. record
  181. members, and so on...
  182. }
  183. TDocNode = class
  184. private
  185. FFirstChild, FNextSibling: TDocNode;
  186. FName: String;
  187. FNode: TDOMElement;
  188. FIsSkipped: Boolean;
  189. FShortDescr: TDOMElement;
  190. FDescr: TDOMElement;
  191. FErrorsDoc: TDOMElement;
  192. FSeeAlso: TDOMElement;
  193. FFirstExample: TDOMElement;
  194. FLink: String;
  195. FTopicNode : Boolean;
  196. FRefCount : Integer;
  197. public
  198. constructor Create(const AName: String; ANode: TDOMElement);
  199. destructor Destroy; override;
  200. Function IncRefcount : Integer;
  201. function FindChild(const APathName: String): TDocNode;
  202. function CreateChildren(const APathName: String): TDocNode;
  203. // Properties for tree structure
  204. property FirstChild: TDocNode read FFirstChild;
  205. property NextSibling: TDocNode read FNextSibling;
  206. // Basic properties
  207. property Name: String read FName;
  208. property Node: TDOMElement read FNode;
  209. // Data fetched from the XML document
  210. property IsSkipped: Boolean read FIsSkipped;
  211. property ShortDescr: TDOMElement read FShortDescr;
  212. property Descr: TDOMElement read FDescr;
  213. property ErrorsDoc: TDOMElement read FErrorsDoc;
  214. property SeeAlso: TDOMElement read FSeeAlso;
  215. property FirstExample: TDOMElement read FFirstExample;
  216. property Link: String read FLink;
  217. Property TopicNode : Boolean Read FTopicNode;
  218. Property RefCount : Integer Read FRefCount;
  219. end;
  220. // The main FPDoc engine
  221. { TFPDocEngine }
  222. TFPDocEngine = class(TPasTreeContainer)
  223. private
  224. protected
  225. DescrDocs: TObjectList; // List of XML documents
  226. DescrDocNames: TStringList; // Names of the XML documents
  227. FRootLinkNode: TLinkNode;
  228. FRootDocNode: TDocNode;
  229. FPackages: TList; // List of TFPPackage objects
  230. CurModule: TPasModule;
  231. CurPackageDocNode: TDocNode;
  232. public
  233. Output: String;
  234. HasContentFile: Boolean;
  235. HidePrivate: Boolean; // Hide private class members in output?
  236. HideProtected: Boolean; // Hide protected class members in output?
  237. WarnNoNode : Boolean; // Warn if no description node found for element.
  238. constructor Create;
  239. destructor Destroy; override;
  240. procedure SetPackageName(const APackageName: String);
  241. procedure ReadContentFile(const AFilename, ALinkPrefix: String);
  242. procedure WriteContentFile(const AFilename: String);
  243. function CreateElement(AClass: TPTreeElement; const AName: String;
  244. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  245. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  246. override;
  247. function FindElement(const AName: String): TPasElement; override;
  248. function FindModule(const AName: String): TPasModule; override;
  249. // Link tree support
  250. procedure AddLink(const APathName, ALinkTo: String);
  251. function FindAbsoluteLink(const AName: String): String;
  252. function ResolveLink(AModule: TPasModule; const ALinkDest: String): String;
  253. function FindLinkedNode(ANode: TDocNode): TDocNode;
  254. // Documentation file support
  255. procedure AddDocFile(const AFilename: String);
  256. // Documentation retrieval
  257. function FindDocNode(AElement: TPasElement): TDocNode;
  258. function FindDocNode(ARefModule: TPasModule; const AName: String): TDocNode;
  259. function FindShortDescr(AElement: TPasElement): TDOMElement;
  260. function FindShortDescr(ARefModule: TPasModule;
  261. const AName: String): TDOMElement;
  262. function GetExampleFilename(const ExElement: TDOMElement): String;
  263. property RootLinkNode: TLinkNode read FRootLinkNode;
  264. property RootDocNode: TDocNode read FRootDocNode;
  265. property Package: TPasPackage read FPackage;
  266. end;
  267. procedure TranslateDocStrings(const Lang: String);
  268. Function IsLinkNode(Node : TDomNode) : Boolean;
  269. Function IsExampleNode(Example : TDomNode) : Boolean;
  270. // returns true is link is an absolute URI
  271. Function IsLinkAbsolute(ALink: String): boolean;
  272. implementation
  273. uses SysUtils, Gettext, XMLRead;
  274. const
  275. AbsoluteLinkPrefixes : array[0..2] of string = ('/', 'http://', 'ms-its:');
  276. { TObjectList }
  277. destructor TObjectList.Destroy;
  278. var
  279. i: Integer;
  280. begin
  281. for i := 0 to Count - 1 do
  282. TObject(Items[i]).Free;
  283. inherited Destroy;
  284. end;
  285. { TLinkNode }
  286. constructor TLinkNode.Create(const AName, ALink: String);
  287. begin
  288. inherited Create;
  289. FName := AName;
  290. FLink := ALink;
  291. end;
  292. destructor TLinkNode.Destroy;
  293. begin
  294. if Assigned(FirstChild) then
  295. FirstChild.Free;
  296. if Assigned(NextSibling) then
  297. NextSibling.Free;
  298. inherited Destroy;
  299. end;
  300. function TLinkNode.FindChild(const APathName: String): TLinkNode;
  301. var
  302. DotPos: Integer;
  303. ChildName: String;
  304. Child: TLinkNode;
  305. begin
  306. if Length(APathName) = 0 then
  307. Result := Self
  308. else
  309. begin
  310. DotPos := Pos('.', APathName);
  311. if DotPos = 0 then
  312. ChildName := APathName
  313. else
  314. ChildName := Copy(APathName, 1, DotPos - 1);
  315. Child := FirstChild;
  316. while Assigned(Child) do
  317. begin
  318. if CompareText(Child.Name, ChildName) = 0 then
  319. begin
  320. if DotPos = 0 then
  321. Result := Child
  322. else
  323. Result := Child.FindChild(
  324. Copy(APathName, DotPos + 1, Length(APathName)));
  325. exit;
  326. end;
  327. Child := Child.NextSibling;
  328. end;
  329. Result := nil;
  330. end;
  331. end;
  332. function TLinkNode.CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  333. var
  334. DotPos: Integer;
  335. ChildName: String;
  336. Child, LastChild: TLinkNode;
  337. begin
  338. if Length(APathName) = 0 then
  339. Result := Self
  340. else
  341. begin
  342. DotPos := Pos('.', APathName);
  343. if DotPos = 0 then
  344. ChildName := APathName
  345. else
  346. ChildName := Copy(APathName, 1, DotPos - 1);
  347. Child := FirstChild;
  348. LastChild := nil;
  349. while Assigned(Child) do
  350. begin
  351. if CompareText(Child.Name, ChildName) = 0 then
  352. begin
  353. if DotPos = 0 then
  354. Result := Child
  355. else
  356. Result := Child.CreateChildren(
  357. Copy(APathName, DotPos + 1, Length(APathName)), ALinkTo);
  358. exit;
  359. end;
  360. LastChild := Child;
  361. Child := Child.NextSibling;
  362. end;
  363. { No child found, let's create one if we are at the end of the path }
  364. if DotPos > 0 then
  365. // !!!: better throw an exception
  366. WriteLn('Link path does not exist: ', APathName);
  367. Result := TLinkNode.Create(ChildName, ALinkTo);
  368. if Assigned(LastChild) then
  369. LastChild.FNextSibling := Result
  370. else
  371. FFirstChild := Result;
  372. end;
  373. end;
  374. { TDocNode }
  375. constructor TDocNode.Create(const AName: String; ANode: TDOMElement);
  376. begin
  377. inherited Create;
  378. FName := AName;
  379. FNode := ANode;
  380. end;
  381. destructor TDocNode.Destroy;
  382. begin
  383. if Assigned(FirstChild) then
  384. FirstChild.Free;
  385. if Assigned(NextSibling) then
  386. NextSibling.Free;
  387. inherited Destroy;
  388. end;
  389. Function TDocNode.IncRefcount : Integer;
  390. begin
  391. Inc(FRefCount);
  392. Result:=FRefCount;
  393. end;
  394. function TDocNode.FindChild(const APathName: String): TDocNode;
  395. var
  396. DotPos: Integer;
  397. ChildName: String;
  398. Child: TDocNode;
  399. begin
  400. if Length(APathName) = 0 then
  401. Result := Self
  402. else
  403. begin
  404. DotPos := Pos('.', APathName);
  405. if DotPos = 0 then
  406. ChildName := APathName
  407. else
  408. ChildName := Copy(APathName, 1, DotPos - 1);
  409. Child := FirstChild;
  410. while Assigned(Child) do
  411. begin
  412. if CompareText(Child.Name, ChildName) = 0 then
  413. begin
  414. if DotPos = 0 then
  415. Result := Child
  416. else
  417. Result := Child.FindChild(
  418. Copy(APathName, DotPos + 1, Length(APathName)));
  419. exit;
  420. end;
  421. Child := Child.NextSibling;
  422. end;
  423. Result := nil;
  424. end;
  425. end;
  426. function TDocNode.CreateChildren(const APathName: String): TDocNode;
  427. var
  428. DotPos: Integer;
  429. ChildName: String;
  430. Child: TDocNode;
  431. begin
  432. if Length(APathName) = 0 then
  433. Result := Self
  434. else
  435. begin
  436. DotPos := Pos('.', APathName);
  437. if DotPos = 0 then
  438. ChildName := APathName
  439. else
  440. ChildName := Copy(APathName, 1, DotPos - 1);
  441. Child := FirstChild;
  442. while Assigned(Child) do
  443. begin
  444. if CompareText(Child.Name, ChildName) = 0 then
  445. begin
  446. if DotPos = 0 then
  447. Result := Child
  448. else
  449. Result := Child.CreateChildren(
  450. Copy(APathName, DotPos + 1, Length(APathName)));
  451. exit;
  452. end;
  453. Child := Child.NextSibling;
  454. end;
  455. // No child found, let's create one
  456. Result := TDocNode.Create(ChildName, nil);
  457. if Assigned(FirstChild) then
  458. begin
  459. Result.FNextSibling := FirstChild;
  460. FFirstChild := Result;
  461. end else
  462. FFirstChild := Result;
  463. if DotPos > 0 then
  464. Result := Result.CreateChildren(
  465. Copy(APathName, DotPos + 1, Length(APathName)));
  466. end;
  467. end;
  468. { TFPDocEngine }
  469. constructor TFPDocEngine.Create;
  470. begin
  471. inherited Create;
  472. DescrDocs := TObjectList.Create;
  473. DescrDocNames := TStringList.Create;
  474. FRootLinkNode := TLinkNode.Create('', '');
  475. FRootDocNode := TDocNode.Create('', nil);
  476. HidePrivate := True;
  477. FPackages := TList.Create;
  478. end;
  479. destructor TFPDocEngine.Destroy;
  480. var
  481. i: Integer;
  482. begin
  483. for i := 0 to FPackages.Count - 1 do
  484. TPasPackage(FPackages[i]).Release;
  485. FPackages.Free;
  486. FRootDocNode.Free;
  487. FRootLinkNode.Free;
  488. DescrDocNames.Free;
  489. DescrDocs.Free;
  490. inherited Destroy;
  491. end;
  492. procedure TFPDocEngine.SetPackageName(const APackageName: String);
  493. begin
  494. ASSERT(not Assigned(Package));
  495. FPackage := TPasPackage(inherited CreateElement(TPasPackage,
  496. '#' + APackageName, nil, '', 0));
  497. FPackages.Add(FPackage);
  498. CurPackageDocNode := RootDocNode.FindChild('#' + APackageName);
  499. If Assigned(CurPackageDocNode) then
  500. CurPackageDocNode.IncRefCount;
  501. end;
  502. procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
  503. var
  504. f: Text;
  505. procedure ReadLinkTree;
  506. var
  507. s: String;
  508. PrevSpaces, ThisSpaces, i, StackIndex: Integer;
  509. CurParent, PrevSibling, NewNode: TLinkNode;
  510. ParentStack, SiblingStack: array[0..7] of TLinkNode;
  511. begin
  512. PrevSpaces := 0;
  513. CurParent := RootLinkNode;
  514. PrevSibling := CurParent.FirstChild;
  515. if assigned(PrevSibling) then
  516. while assigned(PrevSibling.NextSibling) do
  517. PrevSibling := PrevSibling.NextSibling;
  518. StackIndex := 0;
  519. while True do
  520. begin
  521. ReadLn(f, s);
  522. if Length(s) = 0 then
  523. break;
  524. ThisSpaces := 0;
  525. while s[ThisSpaces + 1] = ' ' do
  526. Inc(ThisSpaces);
  527. if ThisSpaces <> PrevSpaces then
  528. begin
  529. if ThisSpaces > PrevSpaces then
  530. begin
  531. { Dive down one level }
  532. ParentStack[StackIndex] := CurParent;
  533. SiblingStack[StackIndex] := PrevSibling;
  534. Inc(StackIndex);
  535. CurParent := PrevSibling;
  536. PrevSibling := nil;
  537. end else
  538. while PrevSpaces > ThisSpaces do
  539. begin
  540. Dec(StackIndex);
  541. CurParent := ParentStack[StackIndex];
  542. PrevSibling := SiblingStack[StackIndex];
  543. Dec(PrevSpaces);
  544. end;
  545. PrevSpaces := ThisSpaces;
  546. end;
  547. i := ThisSpaces + 1;
  548. while s[i] <> ' ' do
  549. Inc(i);
  550. NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
  551. ALinkPrefix + Copy(s, i + 1, Length(s)));
  552. if Assigned(PrevSibling) then
  553. PrevSibling.FNextSibling := NewNode
  554. else
  555. CurParent.FFirstChild := NewNode;
  556. PrevSibling := NewNode;
  557. end;
  558. end;
  559. procedure ReadClasses;
  560. function CreateClass(const AName: String): TPasClassType;
  561. var
  562. DotPos, DotPos2, i: Integer;
  563. s: String;
  564. HPackage: TPasPackage;
  565. Module: TPasModule;
  566. begin
  567. // Find or create package
  568. DotPos := Pos('.', AName);
  569. s := Copy(AName, 1, DotPos - 1);
  570. HPackage := nil;
  571. for i := 0 to FPackages.Count - 1 do
  572. if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
  573. begin
  574. HPackage := TPasPackage(FPackages[i]);
  575. break;
  576. end;
  577. if not Assigned(HPackage) then
  578. begin
  579. HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
  580. '', 0));
  581. FPackages.Add(HPackage);
  582. end;
  583. // Find or create module
  584. DotPos2 := DotPos;
  585. repeat
  586. Inc(DotPos2);
  587. until AName[DotPos2] = '.';
  588. s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
  589. Module := nil;
  590. for i := 0 to HPackage.Modules.Count - 1 do
  591. if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
  592. begin
  593. Module := TPasModule(HPackage.Modules[i]);
  594. break;
  595. end;
  596. if not Assigned(Module) then
  597. begin
  598. Module := TPasModule.Create(s, HPackage);
  599. Module.InterfaceSection := TPasSection.Create('', Module);
  600. HPackage.Modules.Add(Module);
  601. end;
  602. // Create node for class
  603. Result := TPasClassType.Create(Copy(AName, DotPos2 + 1, Length(AName)),
  604. Module.InterfaceSection);
  605. Result.ObjKind := okClass;
  606. Module.InterfaceSection.Declarations.Add(Result);
  607. Module.InterfaceSection.Classes.Add(Result);
  608. end;
  609. var
  610. s, Name: String;
  611. CurClass: TPasClassType;
  612. i: Integer;
  613. Member: TPasElement;
  614. begin
  615. CurClass := nil;
  616. while True do
  617. begin
  618. ReadLn(f, s);
  619. if Length(s) = 0 then
  620. break;
  621. if s[1] = '#' then
  622. begin
  623. // New class
  624. i := Pos(' ', s);
  625. CurClass := CreateClass(Copy(s, 1, i - 1));
  626. end else
  627. begin
  628. i := Pos(' ', s);
  629. if i = 0 then
  630. Name := Copy(s, 3, Length(s))
  631. else
  632. Name := Copy(s, 3, i - 3);
  633. case s[2] of
  634. 'M':
  635. Member := TPasProcedure.Create(Name, CurClass);
  636. 'P':
  637. begin
  638. Member := TPasProperty.Create(Name, CurClass);
  639. if i > 0 then
  640. while i <= Length(s) do
  641. begin
  642. case s[i] of
  643. 'r':
  644. TPasProperty(Member).ReadAccessorName := '<dummy>';
  645. 'w':
  646. TPasProperty(Member).WriteAccessorName := '<dummy>';
  647. 's':
  648. TPasProperty(Member).StoredAccessorName := '<dummy>';
  649. end;
  650. Inc(i);
  651. end;
  652. end;
  653. 'V':
  654. Member := TPasVariable.Create(Name, CurClass);
  655. else
  656. raise Exception.Create('Invalid member type: ' + s[2]);
  657. end;
  658. CurClass.Members.Add(Member);
  659. end;
  660. end;
  661. end;
  662. var
  663. s: String;
  664. begin
  665. if not FileExists(AFileName) then
  666. raise EInOutError.Create('File not found: ' + AFileName);
  667. Assign(f, AFilename);
  668. Reset(f);
  669. while not EOF(f) do
  670. begin
  671. ReadLn(f, s);
  672. if (Length(s) = 0) or (s[1] = '#') then
  673. continue;
  674. if s = ':link tree' then
  675. ReadLinkTree
  676. else if s = ':classes' then
  677. ReadClasses
  678. else
  679. repeat
  680. ReadLn(f, s);
  681. until EOF(f) or (Length(s) = 0);
  682. end;
  683. Close(f);
  684. end;
  685. procedure TFPDocEngine.WriteContentFile(const AFilename: String);
  686. var
  687. ContentFile: Text;
  688. procedure ProcessLinkNode(ALinkNode: TLinkNode; const AIdent: String);
  689. var
  690. ChildNode: TLinkNode;
  691. begin
  692. WriteLn(ContentFile, AIdent, ALinkNode.Name, ' ', ALinkNode.Link);
  693. ChildNode := ALinkNode.FirstChild;
  694. while Assigned(ChildNode) do
  695. begin
  696. ProcessLinkNode(ChildNode, AIdent + ' ');
  697. ChildNode := ChildNode.NextSibling;
  698. end;
  699. end;
  700. var
  701. LinkNode: TLinkNode;
  702. i, j, k: Integer;
  703. Module: TPasModule;
  704. ClassDecl: TPasClassType;
  705. Member: TPasElement;
  706. s: String;
  707. begin
  708. Assign(ContentFile, AFilename);
  709. Rewrite(ContentFile);
  710. try
  711. WriteLn(ContentFile, '# FPDoc Content File');
  712. WriteLn(ContentFile, ':link tree');
  713. LinkNode := RootLinkNode.FirstChild;
  714. while Assigned(LinkNode) do
  715. begin
  716. if LinkNode.Name = Package.Name then
  717. begin
  718. ProcessLinkNode(LinkNode, '');
  719. end;
  720. LinkNode := LinkNode.NextSibling;
  721. end;
  722. if Assigned(Package) then
  723. begin
  724. WriteLn(ContentFile);
  725. WriteLn(ContentFile, ':classes');
  726. for i := 0 to Package.Modules.Count - 1 do
  727. begin
  728. Module := TPasModule(Package.Modules[i]);
  729. for j := 0 to Module.InterfaceSection.Classes.Count - 1 do
  730. begin
  731. ClassDecl := TPasClassType(Module.InterfaceSection.Classes[j]);
  732. Write(ContentFile, ClassDecl.PathName, ' ');
  733. if Assigned(ClassDecl.AncestorType) then
  734. WriteLn(ContentFile, ClassDecl.AncestorType.PathName)
  735. else if ClassDecl.ObjKind = okClass then
  736. WriteLn(ContentFile, '.TObject');
  737. for k := 0 to ClassDecl.Members.Count - 1 do
  738. begin
  739. Member := TPasElement(ClassDecl.Members[k]);
  740. Write(ContentFile, Chr(Ord(Member.Visibility) + Ord('0')));
  741. SetLength(s, 0);
  742. if Member.ClassType = TPasVariable then
  743. Write(ContentFile, 'V')
  744. else if Member.ClassType = TPasProperty then
  745. begin
  746. Write(ContentFile, 'P');
  747. if Length(TPasProperty(Member).ReadAccessorName) > 0 then
  748. s := s + 'r';
  749. if Length(TPasProperty(Member).WriteAccessorName) > 0 then
  750. s := s + 'w';
  751. if Length(TPasProperty(Member).StoredAccessorName) > 0 then
  752. s := s + 's';
  753. end else
  754. Write(ContentFile, 'M'); // Member must be a method
  755. Write(ContentFile, Member.Name);
  756. if Length(s) > 0 then
  757. WriteLn(ContentFile, ' ', s)
  758. else
  759. WriteLn(ContentFile);
  760. end;
  761. end;
  762. end;
  763. end;
  764. finally
  765. Close(ContentFile);
  766. end;
  767. end;
  768. function TFPDocEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  769. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  770. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  771. begin
  772. Result := AClass.Create(AName, AParent);
  773. Result.Visibility := AVisibility;
  774. if AClass.InheritsFrom(TPasModule) then
  775. CurModule := TPasModule(Result);
  776. Result.SourceFilename := ASourceFilename;
  777. Result.SourceLinenumber := ASourceLinenumber;
  778. end;
  779. function TFPDocEngine.FindElement(const AName: String): TPasElement;
  780. function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
  781. var
  782. l: TList;
  783. i: Integer;
  784. begin
  785. If assigned(AModule.InterfaceSection) and
  786. Assigned(AModule.InterfaceSection.Declarations) then
  787. begin
  788. l:=AModule.InterfaceSection.Declarations;
  789. for i := 0 to l.Count - 1 do
  790. begin
  791. Result := TPasElement(l[i]);
  792. if CompareText(Result.Name, LocalName) = 0 then
  793. exit;
  794. end;
  795. end;
  796. Result := nil;
  797. end;
  798. var
  799. i: Integer;
  800. //ModuleName, LocalName: String;
  801. Module: TPasElement;
  802. begin
  803. {!!!: Don't know if we ever will have to use the following:
  804. i := Pos('.', AName);
  805. if i <> 0 then
  806. begin
  807. WriteLn('Dot found in name: ', AName);
  808. Result := nil;
  809. end else
  810. begin}
  811. Result := FindInModule(CurModule, AName);
  812. if not Assigned(Result) then
  813. for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
  814. begin
  815. Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
  816. if Module.ClassType = TPasModule then
  817. begin
  818. Result := FindInModule(TPasModule(Module), AName);
  819. if Assigned(Result) then
  820. exit;
  821. end;
  822. end;
  823. {end;}
  824. end;
  825. function TFPDocEngine.FindModule(const AName: String): TPasModule;
  826. function FindInPackage(APackage: TPasPackage): TPasModule;
  827. var
  828. i: Integer;
  829. begin
  830. for i := 0 to APackage.Modules.Count - 1 do
  831. begin
  832. Result := TPasModule(APackage.Modules[i]);
  833. if CompareText(Result.Name, AName) = 0 then
  834. exit;
  835. end;
  836. Result := nil;
  837. end;
  838. var
  839. i: Integer;
  840. begin
  841. Result := FindInPackage(Package);
  842. if not Assigned(Result) then
  843. for i := FPackages.Count - 1 downto 0 do
  844. begin
  845. if TPasPackage(FPackages[i]) = Package then
  846. continue;
  847. Result := FindInPackage(TPasPackage(FPackages[i]));
  848. if Assigned(Result) then
  849. exit;
  850. end;
  851. end;
  852. procedure TFPDocEngine.AddLink(const APathName, ALinkTo: String);
  853. begin
  854. RootLinkNode.CreateChildren(APathName, ALinkTo);
  855. end;
  856. function TFPDocEngine.FindAbsoluteLink(const AName: String): String;
  857. var
  858. LinkNode: TLinkNode;
  859. begin
  860. LinkNode := RootLinkNode.FindChild(AName);
  861. if Assigned(LinkNode) then
  862. Result := LinkNode.Link
  863. else
  864. SetLength(Result, 0);
  865. end;
  866. function TFPDocEngine.ResolveLink(AModule: TPasModule;
  867. const ALinkDest: String): String;
  868. var
  869. i: Integer;
  870. ThisPackage: TLinkNode;
  871. UnitList: TList;
  872. begin
  873. //WriteLn('ResolveLink(', ALinkDest, ')... ');
  874. if Length(ALinkDest) = 0 then
  875. begin
  876. SetLength(Result, 0);
  877. exit;
  878. end;
  879. if (ALinkDest[1] = '#') or (not assigned(AModule)) then
  880. Result := FindAbsoluteLink(ALinkDest)
  881. else
  882. begin
  883. Result := ResolveLink(AModule, AModule.PathName + '.' + ALinkDest);
  884. if Length(Result) > 0 then
  885. exit;
  886. { Try all packages }
  887. SetLength(Result, 0);
  888. ThisPackage := RootLinkNode.FirstChild;
  889. while Assigned(ThisPackage) do
  890. begin
  891. Result := ResolveLink(AModule, ThisPackage.Name + '.' + ALinkDest);
  892. if Length(Result) > 0 then
  893. exit;
  894. ThisPackage := ThisPackage.NextSibling;
  895. end;
  896. if Length(Result) = 0 then
  897. begin
  898. { Okay, then we have to try all imported units of the current module }
  899. UnitList := AModule.InterfaceSection.UsesList;
  900. for i := UnitList.Count - 1 downto 0 do
  901. begin
  902. { Try all packages }
  903. ThisPackage := RootLinkNode.FirstChild;
  904. while Assigned(ThisPackage) do
  905. begin
  906. Result := ResolveLink(AModule, ThisPackage.Name + '.' +
  907. TPasType(UnitList[i]).Name + '.' + ALinkDest);
  908. if Length(Result) > 0 then
  909. exit;
  910. ThisPackage := ThisPackage.NextSibling;
  911. end;
  912. end;
  913. end;
  914. end;
  915. if Length(Result) = 0 then
  916. for i := Length(ALinkDest) downto 1 do
  917. if ALinkDest[i] = '.' then
  918. begin
  919. Result := ResolveLink(AModule, Copy(ALinkDest, 1, i - 1));
  920. exit;
  921. end;
  922. end;
  923. procedure TFPDocEngine.AddDocFile(const AFilename: String);
  924. function ReadNode(OwnerDocNode: TDocNode; Element: TDOMElement): TDocNode;
  925. var
  926. Subnode: TDOMNode;
  927. begin
  928. if OwnerDocNode = RootDocNode then
  929. Result := OwnerDocNode.CreateChildren('#' + Element['name'])
  930. else
  931. Result := OwnerDocNode.CreateChildren(Element['name']);
  932. Result.FNode := Element;
  933. Result.FLink := Element['link'];
  934. Result.FIsSkipped := Element['skip'] = '1';
  935. Subnode := Element.FirstChild;
  936. while Assigned(Subnode) do
  937. begin
  938. if Subnode.NodeType = ELEMENT_NODE then
  939. begin
  940. if Subnode.NodeName = 'short' then
  941. Result.FShortDescr := TDOMElement(Subnode)
  942. else if Subnode.NodeName = 'descr' then
  943. Result.FDescr := TDOMElement(Subnode)
  944. else if Subnode.NodeName = 'errors' then
  945. Result.FErrorsDoc := TDOMElement(Subnode)
  946. else if Subnode.NodeName = 'seealso' then
  947. Result.FSeeAlso := TDOMElement(Subnode)
  948. else if (Subnode.NodeName = 'example') and
  949. not Assigned(Result.FirstExample) then
  950. Result.FFirstExample := TDOMElement(Subnode);
  951. end;
  952. Subnode := Subnode.NextSibling;
  953. end;
  954. end;
  955. Procedure ReadTopics(TopicNode : TDocNode);
  956. Var
  957. SubNode : TDOMNode;
  958. begin
  959. SubNode:=TopicNode.FNode.FirstChilD;
  960. While Assigned(SubNode) do
  961. begin
  962. If (SubNode.NodeType=ELEMENT_NODE) and (SubNode.NodeName='topic') then
  963. With ReadNode(TopicNode,TDomElement(SubNode)) do
  964. // We could allow recursion here, but we won't, because it doesn't work on paper.
  965. FTopicNode:=True;
  966. SubNode:=Subnode.NextSibling;
  967. end;
  968. end;
  969. var
  970. i: Integer;
  971. Node, Subnode, Subsubnode: TDOMNode;
  972. Element: TDOMElement;
  973. Doc: TXMLDocument;
  974. PackageDocNode, TopicNode,ModuleDocNode: TDocNode;
  975. begin
  976. ReadXMLFile(Doc, AFilename);
  977. DescrDocs.Add(Doc);
  978. DescrDocNames.Add(AFilename);
  979. Node := Doc.DocumentElement.FirstChild;
  980. while Assigned(Node) do
  981. begin
  982. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'package') then
  983. begin
  984. PackageDocNode := ReadNode(RootDocNode, TDOMElement(Node));
  985. PackageDocNode.IncRefCount;
  986. // Scan all 'module' elements within this package element
  987. Subnode := Node.FirstChild;
  988. while Assigned(Subnode) do
  989. begin
  990. if (Subnode.NodeType = ELEMENT_NODE) then
  991. begin
  992. If (Subnode.NodeName = 'module') then
  993. begin
  994. ModuleDocNode := ReadNode(PackageDocNode, TDOMElement(Subnode));
  995. // Scan all 'element' elements within this module element
  996. Subsubnode := Subnode.FirstChild;
  997. while Assigned(Subsubnode) do
  998. begin
  999. if (Subsubnode.NodeType = ELEMENT_NODE) then
  1000. begin
  1001. if (Subsubnode.NodeName = 'element') then
  1002. ReadNode(ModuleDocNode, TDOMElement(Subsubnode))
  1003. else if (SubSubNode.NodeName='topic') then
  1004. begin
  1005. TopicNode:=ReadNode(ModuleDocNode,TDomElement(SubSubNode));
  1006. TopicNode.FTopicNode:=True;
  1007. ReadTopics(TopicNode);
  1008. end;
  1009. end;
  1010. Subsubnode := Subsubnode.NextSibling;
  1011. end;
  1012. end
  1013. else if (SubNode.NodeName='topic') then
  1014. begin
  1015. TopicNode:=ReadNode(PackageDocNode,TDomElement(SubNode));
  1016. TopicNode.FTopicNode:=True;
  1017. ReadTopics(TopicNode);
  1018. end;
  1019. end;
  1020. Subnode := Subnode.NextSibling;
  1021. end;
  1022. end;
  1023. Node := Node.NextSibling;
  1024. end;
  1025. end;
  1026. function TFPDocEngine.FindDocNode(AElement: TPasElement): TDocNode;
  1027. begin
  1028. Result:=Nil;
  1029. If Assigned(AElement) then
  1030. begin
  1031. if AElement.InheritsFrom(TPasUnresolvedTypeRef) then
  1032. Result := FindDocNode(AElement.GetModule, AElement.Name)
  1033. else
  1034. Result := RootDocNode.FindChild(AElement.PathName);
  1035. if (Result=Nil) and
  1036. WarnNoNode and
  1037. (Length(AElement.PathName)>0) and
  1038. (AElement.PathName[1]='#') then
  1039. Writeln('No documentation node found for identifier : ',AElement.PathName);
  1040. end;
  1041. end;
  1042. function TFPDocEngine.FindDocNode(ARefModule: TPasModule;
  1043. const AName: String): TDocNode;
  1044. var
  1045. CurPackage: TDocNode;
  1046. UnitList: TList;
  1047. i: Integer;
  1048. begin
  1049. if Length(AName) = 0 then
  1050. Result := nil
  1051. else
  1052. begin
  1053. if AName[1] = '#' then
  1054. Result := RootDocNode.FindChild(AName)
  1055. else
  1056. Result := RootDocNode.FindChild(Package.Name + '.' + AName);
  1057. if (not Assigned(Result)) and Assigned(ARefModule) then
  1058. Result := RootDocNode.FindChild(ARefModule.PathName + '.' + AName);
  1059. if (not Assigned(Result)) and (AName[1] <> '#') then
  1060. begin
  1061. CurPackage := RootDocNode.FirstChild;
  1062. while Assigned(CurPackage) do
  1063. begin
  1064. Result := RootDocNode.FindChild(CurPackage.Name + '.' + AName);
  1065. if Assigned(Result) then
  1066. break;
  1067. CurPackage := CurPackage.NextSibling;
  1068. end;
  1069. if not Assigned(Result) then
  1070. begin
  1071. { Okay, then we have to try all imported units of the current module }
  1072. UnitList := CurModule.InterfaceSection.UsesList;
  1073. for i := UnitList.Count - 1 downto 0 do
  1074. begin
  1075. { Try all packages }
  1076. CurPackage := RootDocNode.FirstChild;
  1077. while Assigned(CurPackage) do
  1078. begin
  1079. Result := RootDocNode.FindChild(CurPackage.Name + '.' +
  1080. TPasType(UnitList[i]).Name + '.' + AName);
  1081. if Assigned(Result) then
  1082. break;
  1083. CurPackage := CurPackage.NextSibling;
  1084. end;
  1085. end;
  1086. end;
  1087. end;
  1088. end;
  1089. end;
  1090. function TFPDocEngine.FindShortDescr(AElement: TPasElement): TDOMElement;
  1091. var
  1092. DocNode,N: TDocNode;
  1093. begin
  1094. DocNode := FindDocNode(AElement);
  1095. if Assigned(DocNode) then
  1096. begin
  1097. N:=FindLinkedNode(DocNode);
  1098. If (N<>Nil) then
  1099. DocNode:=N;
  1100. Result := DocNode.ShortDescr;
  1101. end
  1102. else
  1103. Result := nil;
  1104. end;
  1105. function TFPDocEngine.FindLinkedNode(ANode : TDocNode) : TDocNode;
  1106. Var
  1107. S: String;
  1108. begin
  1109. If (ANode.Link='') then
  1110. Result:=Nil
  1111. else
  1112. Result:=FindDocNode(CurModule,ANode.Link);
  1113. end;
  1114. function TFPDocEngine.FindShortDescr(ARefModule: TPasModule;
  1115. const AName: String): TDOMElement;
  1116. var
  1117. N,DocNode: TDocNode;
  1118. begin
  1119. DocNode := FindDocNode(ARefModule, AName);
  1120. if Assigned(DocNode) then
  1121. begin
  1122. N:=FindLinkedNode(DocNode);
  1123. If (N<>Nil) then
  1124. DocNode:=N;
  1125. Result := DocNode.ShortDescr;
  1126. end
  1127. else
  1128. Result := nil;
  1129. end;
  1130. function TFPDocEngine.GetExampleFilename(const ExElement: TDOMElement): String;
  1131. var
  1132. i: Integer;
  1133. fn : String;
  1134. begin
  1135. Result:='';
  1136. for i := 0 to DescrDocs.Count - 1 do
  1137. begin
  1138. Fn:=ExElement['file'];
  1139. if (FN<>'') and (TDOMDocument(DescrDocs[i]) = ExElement.OwnerDocument) then
  1140. begin
  1141. Result := ExtractFilePath(DescrDocNames[i]) + FN;
  1142. if (ExtractFileExt(Result)='') then
  1143. Result:=Result+'.pp';
  1144. end;
  1145. end;
  1146. end;
  1147. { Global helpers }
  1148. procedure TranslateDocStrings(const Lang: String);
  1149. Const
  1150. {$ifdef unix}
  1151. DefDir = '/usr/local/share/locale';
  1152. {$else}
  1153. DefDir = 'intl';
  1154. {$endif}
  1155. var
  1156. mo: TMOFile;
  1157. dir : string;
  1158. begin
  1159. dir:=modir;
  1160. If Dir='' then
  1161. Dir:=DefDir;
  1162. Dir:=IncludeTrailingPathDelimiter(Dir);
  1163. {$IFDEF Unix}
  1164. mo := TMOFile.Create(Format(Dir+'%s/LC_MESSAGES/dglobals.mo', [Lang]));
  1165. {$ELSE}
  1166. mo := TMOFile.Create(Format(Dir+'dglobals.%s.mo', [Lang]));
  1167. {$ENDIF}
  1168. try
  1169. TranslateResourceStrings(mo);
  1170. finally
  1171. mo.Free;
  1172. end;
  1173. end;
  1174. Function IsLinkNode(Node : TDomNode) : Boolean;
  1175. begin
  1176. Result:=Assigned(Node) and (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link');
  1177. end;
  1178. Function IsExampleNode(Example : TDomNode) : Boolean;
  1179. begin
  1180. Result:=Assigned(Example) and (Example.NodeType = ELEMENT_NODE) and (Example.NodeName = 'example')
  1181. end;
  1182. function IsLinkAbsolute(ALink: String): boolean;
  1183. var
  1184. i: integer;
  1185. begin
  1186. Result := false;
  1187. for i := low(AbsoluteLinkPrefixes) to high(AbsoluteLinkPrefixes) do
  1188. if CompareText(AbsoluteLinkPrefixes[i], copy(ALink,1,length(AbsoluteLinkPrefixes[i])))=0 then begin
  1189. Result := true;
  1190. break;
  1191. end;
  1192. end;
  1193. initialization
  1194. LEOL:=Length(LineEnding);
  1195. end.