dglobals.pp 39 KB

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