dglobals.pp 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813
  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, uriparser, SysUtils;
  20. Const
  21. CacheSize = 20;
  22. ContentBufSize = 4096 * 8;
  23. Var
  24. LEOL : Integer;
  25. modir : string;
  26. resourcestring
  27. // Output strings
  28. SDocPackageTitle = 'Reference for package ''%s''';
  29. SDocPackageMenuTitle = 'Package ''%s''';
  30. SDocPackageLinkTitle = 'Package';
  31. SDocPrograms = 'Programs';
  32. SDocUnits = 'Units';
  33. SDocUnitTitle = 'Reference for unit ''%s''';
  34. SDocUnitMenuTitle = 'Unit ''%s''';
  35. SDocInheritanceHierarchy = 'Inheritance Hierarchy';
  36. SDocInterfaceSection = 'Interface section';
  37. SDocImplementationSection = 'Implementation section';
  38. SDocUsedUnits = 'Used units';
  39. SDocUsedUnitsByUnitXY = 'Used units by unit ''%s''';
  40. SDocConstsTypesVars = 'Constants, types and variables';
  41. SDocResStrings = 'Resource strings';
  42. SDocTypes = 'Types';
  43. SDocType = 'Type';
  44. SDocConstants = 'Constants';
  45. SDocConstant = 'Constant';
  46. SDocClasses = 'Classes';
  47. SDocClass = 'Class';
  48. SDocProceduresAndFunctions = 'Procedures and functions';
  49. SDocProcedureOrFunction = 'Procedure/function';
  50. SDocVariables = 'Variables';
  51. SDocVariable = 'Variable';
  52. SDocIdentifierIndex = 'Index';
  53. SDocPackageClassHierarchy = 'Class hierarchy';
  54. SDocModuleIndex = 'Index of all identifiers in unit ''%s''';
  55. SDocPackageIndex = 'Index of all identifiers in package ''%s''';
  56. SDocUnitOverview = 'Overview of unit ''%s''';
  57. SDocOverview = 'Overview';
  58. SDocSearch = 'Search';
  59. SDocDeclaration = 'Declaration';
  60. SDocDescription = 'Description';
  61. SDocErrors = 'Errors';
  62. SDocVersion = 'Version info';
  63. SDocSeeAlso = 'See also';
  64. SDocExample = 'Example';
  65. SDocArguments = 'Arguments';
  66. SDocFunctionResult = 'Function result';
  67. SDocRemark = 'Remark: ';
  68. SDocMethodOverview = 'Method overview';
  69. SDocPropertyOverview = 'Property overview';
  70. SDocEventOverview = 'Event overview';
  71. SDocInterfacesOverview = 'Interfaces overview';
  72. SDocInterface = 'Interfaces';
  73. SDocPage = 'Page';
  74. SDocMember = 'Member';
  75. SDocMembers = 'Members';
  76. SDocField = 'Field';
  77. SDocMethod = 'Method';
  78. SDocProperty = 'Property';
  79. SDocAccess = 'Access';
  80. SDocInheritance = 'Inheritance';
  81. SDocProperties = 'Properties';
  82. SDocMethods = 'Methods';
  83. SDocEvents = 'Events';
  84. SDocByName = 'by Name';
  85. SDocByInheritance = 'By inheritance';
  86. SDocValue = 'Value';
  87. SDocExplanation = 'Explanation';
  88. SDocProcedure = 'Procedure';
  89. SDocValuesForEnum = 'Enumeration values for type %s';
  90. SDocSourcePosition = 'Source position: %s line %d';
  91. SDocSynopsis = 'Synopsis';
  92. SDocVisibility = 'Visibility';
  93. SDocOpaque = 'Opaque type';
  94. SDocDateGenerated = 'Documentation generated on: %s';
  95. // The next line requires leading/trailing space due to XML comment layout:
  96. SDocGeneratedByComment = ' Generated using FPDoc - (c) 2000-2012 FPC contributors and Sebastian Guenther, [email protected] ';
  97. SDocNotes = 'Notes';
  98. SDocName = 'Name';
  99. SDocType_s = 'Type(s)';
  100. SDocTopic = 'Topic';
  101. SDocNoneAVailable = 'No members available';
  102. // Topics
  103. SDocRelatedTopics = 'Related topics';
  104. SDocUp = 'Up';
  105. SDocNext = 'Next';
  106. SDocPrevious = 'Previous';
  107. // Various backend constants
  108. SDocChapter = 'Chapter';
  109. SDocSection = 'Section';
  110. SDocSubSection = 'Subsection';
  111. SDocTable = 'Table';
  112. SDocListing = 'Listing';
  113. // Man page usage
  114. SManUsageManSection = 'Use ASection as the man page section';
  115. SManUsageNoUnitPrefix = 'Do not prefix man pages with unit name.';
  116. SManUsageWriterDescr = 'UNIX man page output.';
  117. SManUsagePackageDescription = 'Use descr as the description of man pages';
  118. // HTML usage
  119. SHTMLUsageFooter = 'Append xhtml (@filename reads from file) as footer to html page';
  120. SHTMLUsageNavigator = 'Append xhtml (@filename reads from file) in navigator bar';
  121. SHTMLUsageHeader = 'Append xhtml (@filename reads from file) as header to html page below navigation bar';
  122. SHTMLUsageFooterDate = 'Append footer with date. fmt is Optional format for FormatDateTime';
  123. SHTMLUsageCharset = 'Set the HTML character set';
  124. SHTMLHtmlSearch = 'Add search page with given name to the menu bar';
  125. SHTMLIndexColcount = 'Use N columns in the identifier index pages';
  126. SHTMLImageUrl = 'Prefix image URLs with url';
  127. SHTMLDisableMenuBrackets = 'Disable ''['' and '']'' characters around menu items at the top of the page. Useful for custom css';
  128. // CHM usage
  129. SCHMUsageTOC = 'Use [File] as the table of contents. Usually a .hhc file.';
  130. SCHMUsageIndex = 'Use [File] as the index. Usually a .hhk file.';
  131. SCHMUsageDefPage = 'Set the "Home" page relative to where it lives in the chm. i.e. "/index.html"';
  132. SCHMUsageOtrFiles= 'A txt file containing a list of files to be added relative to the working directory.';
  133. SCHMUsageCSSFile = 'Filename of a .css file to be included in the chm.';
  134. SCHMUsageAutoTOC = 'Automatically generate a Table of Contents. Ignores --toc-file';
  135. SCHMUsageAutoIDX = 'Automatically generate an Index. Ignores --index-file';
  136. SCHMUsageMakeSearch = 'Automatically generate a Search Index from filenames that match *.htm*';
  137. SCHMUsageChmTitle= 'Title of the chm. Defaults to the value from --package';
  138. // MarkDown usage
  139. SMDUsageFooter = 'Append markdown (@filename reads from file) as footer to every markdown page';
  140. SMDUsageHeader = 'Prepend markdown (@filename reads from file) as header to every markdown page';
  141. SMDIndexColcount = 'Use N columns in the identifier index pages';
  142. SMDImageUrl = 'Prefix image URLs with url';
  143. SMDTheme = 'Use name as theme name';
  144. SMDNavigation = 'Use scheme for navigation tree, here scheme is one of:';
  145. SMDNavSubtree = ' UnitSubTree : put all units in a sub tree of a Units node';
  146. SMDNavTree = ' UnitTree : put every units as a node on the same level as packages node';
  147. SXMLUsageFlatStructure = 'Use a flat output structure of XML files and directories';
  148. SXMLUsageSource = 'Include source file and line info in generated XML';
  149. // Linear usage
  150. SLinearUsageDupLinkedDocsP1 = 'Duplicate linked element documentation in';
  151. SLinearUsageDupLinkedDocsP2 = 'descendant classes.';
  152. STitle = 'FPDoc - Free Pascal Documentation Tool';
  153. SVersion = 'Version %s [%s]';
  154. SCopyright1 = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]';
  155. SCopyright2 = '(c) 2005 - 2012 various FPC contributors';
  156. SCmdLineHelp = 'Usage: %s [options]';
  157. SUsageOption008 = '--base-descr-dir=DIR prefix all description files with this directory';
  158. SUsageOption009 = '--base-input-dir=DIR prefix all input files with this directory';
  159. SUsageOption010 = '--content Create content file for package cross-references';
  160. SUsageOption020 = '--cputarget=value Set the target CPU for the scanner.';
  161. SUsageOption030 = '--descr=file use file as description file, e.g.: ';
  162. SUsageOption035 = ' --descr=c:\WIP\myzipperdoc.xml';
  163. SUsageOption040 = ' This option is allowed more than once';
  164. SUsageOption050 = '--descr-dir=Dir Add All XML files in Dir to list of description files';
  165. SUsageOption060 = '--format=fmt Select output format.';
  166. SUsageOption070 = '--help Show this help.';
  167. SUsageOption080 = '--hide-protected Do not show protected methods in overview';
  168. SUsageOption090 = '--import=file Import content file for package cross-references';
  169. SUsageOption100 = '--input=cmd use cmd as input for the parser, e.g.:';
  170. SUsageOption110 = ' --input=C:\fpc\packages\paszlib\src\zipper.pp';
  171. SUsageOption120 = ' At least one input option is required.';
  172. SUsageOption130 = '--input-dir=Dir Add All *.pp and *.pas files in Dir to list of input files';
  173. SUsageOption140 = '--lang=lng Select output language.';
  174. SUsageOption145 = '--macro=name=value Define a macro to preprocess the project file with.';
  175. SUsageOption150 = '--ostarget=value Set the target OS for the scanner.';
  176. SUsageOption160 = '--output=name use name as the output name.';
  177. SUsageOption170 = ' Each backend interprets this as needed.';
  178. SUsageOption180 = '--package=name Set the package name for which to create output,';
  179. SUsageOption190 = ' e.g. --package=fcl';
  180. SUsageOption200 = '--project=file Use file as project file';
  181. SUsageOption210 = '--show-private Show private methods.';
  182. SUsageOption215 = '--stop-on-parser-error';
  183. SUsageOption215A = ' Stop when a parser error occurs. Default is to ignore parser errors.';
  184. SUsageOption220 = '--warn-no-node Warn if no documentation node was found.';
  185. SUsageOption230 = '--mo-dir=dir Set directory where language files reside to dir';
  186. SUsageOption240 = '--parse-impl (Experimental) try to parse implementation too';
  187. SUsageOption250 = '--dont-trim Do not trim XML contents. Useful for preserving';
  188. SUsageOption260 = ' formatting inside e.g <pre> tags';
  189. SUsageOption270 = '--write-project=file';
  190. SUsageOption280 = ' Do not write documentation, create project file instead';
  191. SUsageOption290 = '--verbose Write more information on the screen';
  192. SUsageOption300 = '--dry-run Only parse sources and XML, do not create output';
  193. SUsageOption310 = '--write-project=file';
  194. SUsageOption320 = ' Write all command-line options to a project file';
  195. SUsageFormats = 'The following output formats are supported by this fpdoc:';
  196. SUsageBackendHelp = 'Specify an output format, combined with --help to get more help for this backend.';
  197. SUsageFormatSpecific = 'Output format "%s" supports the following options:';
  198. SCmdLineErrInvalidMacro = 'Macro needs to be in the form name=value';
  199. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  200. SCmdLineInvalidFormat = 'Invalid format "%s" specified';
  201. SCmdLineOutputOptionMissing = 'Need an output filename, please specify one with --output=<filename>';
  202. SWritingPages = 'Writing %d pages...';
  203. SNeedPackageName = 'No package name specified. Please specify one using the --package option.';
  204. SAvailablePackages = 'Available packages: ';
  205. SDone = 'Done.';
  206. SErrCouldNotCreateOutputDir = 'Could not create output directory "%s"';
  207. SErrCouldNotCreateFile = 'Could not create file "%s": %s';
  208. SSeeURL = '(See %s)'; // For linear text writers.
  209. SParsingUsedUnit = 'Parsing used unit "%s" with commandLine "%s"';
  210. Const
  211. SVisibility: array[TPasMemberVisibility] of string =
  212. ('Default', 'Private', 'Protected', 'Public',
  213. 'Published', 'Automated','Strict Private','Strict Protected',
  214. 'Required', 'Optional' // ObjCClass
  215. );
  216. type
  217. TBufType = Array[1..ContentBufSize-1] of byte;
  218. // Assumes a list of TObject instances and frees them on destruction
  219. TObjectList = class(TFPList)
  220. public
  221. destructor Destroy; override;
  222. end;
  223. TPasExternalClassType = Class(TPasClassType);
  224. TPasExternalModule = Class(TPasModule);
  225. { Link entry tree
  226. TFPDocEngine stores the root of the entry tree in its property
  227. "RootLinkNode". The root has one child node for each package, for which
  228. documentation links are available. The children of a package node
  229. are module nodes; and the children of a module node are the top-level
  230. declarations of this module; the next level in the tree stores e.g. record
  231. members, and so on...
  232. }
  233. TLinkNode = class
  234. private
  235. FFirstChild, FNextSibling: TLinkNode;
  236. FName: String;
  237. FLink: String;
  238. public
  239. constructor Create(const AName, ALink: String);
  240. destructor Destroy; override;
  241. function FindChild(const APathName: String): TLinkNode;
  242. function CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  243. // Properties for tree structure
  244. property FirstChild: TLinkNode read FFirstChild;
  245. property NextSibling: TLinkNode read FNextSibling;
  246. // Link properties
  247. property Name: String read FName;
  248. property Link: String read FLink;
  249. end;
  250. { Documentation entry tree
  251. TFPDocEngine stores the root of the entry tree in its property
  252. "RootDocNode". The root has one child node for each package, for which
  253. documentation is being provided by the user. The children of a package node
  254. are module nodes; and the children of a module node are the top-level
  255. declarations of this module; the next level in the tree stores e.g. record
  256. members, and so on...
  257. }
  258. { TDocNode }
  259. TDocNode = class
  260. private
  261. FFirstChild, FNextSibling: TDocNode;
  262. FName: String;
  263. FNode: TDOMElement;
  264. FIsSkipped: Boolean;
  265. FShortDescr: TDOMElement;
  266. FDescr: TDOMElement;
  267. FErrorsDoc: TDOMElement;
  268. FSeeAlso: TDOMElement;
  269. FFirstExample: TDOMElement;
  270. FNotes : TDomElement;
  271. FLink: String;
  272. FTopicNode : Boolean;
  273. FRefCount : Integer;
  274. FVersion: TDomElement;
  275. public
  276. constructor Create(const AName: String; ANode: TDOMElement);
  277. destructor Destroy; override;
  278. Function IncRefcount : Integer;
  279. function FindChild(const APathName: String): TDocNode;
  280. function CreateChildren(const APathName: String): TDocNode;
  281. // Properties for tree structure
  282. property FirstChild: TDocNode read FFirstChild;
  283. property NextSibling: TDocNode read FNextSibling;
  284. // Basic properties
  285. property Name: String read FName;
  286. property Node: TDOMElement read FNode;
  287. // Data fetched from the XML document
  288. property IsSkipped: Boolean read FIsSkipped;
  289. property ShortDescr: TDOMElement read FShortDescr;
  290. property Descr: TDOMElement read FDescr;
  291. property ErrorsDoc: TDOMElement read FErrorsDoc;
  292. Property Version : TDomElement Read FVersion;
  293. property SeeAlso: TDOMElement read FSeeAlso;
  294. property FirstExample: TDOMElement read FFirstExample;
  295. property Notes : TDOMElement read FNotes;
  296. property Link: String read FLink;
  297. Property TopicNode : Boolean Read FTopicNode;
  298. Property RefCount : Integer Read FRefCount;
  299. end;
  300. // The main FPDoc engine
  301. TFPDocLogLevel = (dleWarnNoNode);
  302. TFPDocLogLevels = set of TFPDocLogLevel;
  303. TOnParseUnitEvent = Procedure (Sender : TObject; Const AUnitName : String; Out AInputFile,OSTarget,CPUTarget : String) of Object;
  304. { TFPDocEngine }
  305. TFPDocEngine = class(TPasTreeContainer)
  306. private
  307. FDocLogLevels: TFPDocLogLevels;
  308. FOnParseUnit: TOnParseUnitEvent;
  309. function ResolveLinkInPackages(AModule: TPasModule; const ALinkDest: String; Strict: Boolean=False): String;
  310. function ResolveLinkInUsedUnits(AModule: TPasModule; const ALinkDest: String; Strict: Boolean=False): String;
  311. protected
  312. FAlwaysVisible : TStringList;
  313. DescrDocs: TObjectList; // List of XML documents
  314. DescrDocNames: TStringList; // Names of the XML documents
  315. FRootLinkNode: TLinkNode; // Global tree of TlinkNode from the imported .xct files
  316. FRootDocNode: TDocNode; // Global tree of TDocNode from the .xml documentation files
  317. FPackages: TFPList; // Global list of TPasPackage objects and full tree of sources
  318. CurModule: TPasModule;
  319. CurPackageDocNode: TDocNode;
  320. function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual;
  321. Function LogEvent(E : TFPDocLogLevel) : Boolean;
  322. Procedure DoLog(Const Msg : String);overload;
  323. Procedure DoLog(Const Fmt : String; Args : Array of const);overload;
  324. public
  325. Output: String;
  326. HasContentFile: Boolean;
  327. HidePrivate: Boolean; // Hide private class members in output?
  328. HideProtected: Boolean; // Hide protected class members in output?
  329. WarnNoNode : Boolean; // Warn if no description node found for element.
  330. constructor Create;
  331. destructor Destroy; override;
  332. procedure SetPackageName(const APackageName: String);
  333. // The process importing of objects from external .xct file
  334. procedure ReadContentFile(const AFilename, ALinkPrefix: String);
  335. // Creation of an own .xct output file
  336. procedure WriteContentFile(const AFilename: String);
  337. function CreateElement(AClass: TPTreeElement; const AName: String;
  338. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  339. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  340. override;
  341. function FindInModule(const AName: String ; AModule: TPasModule): TPasElement;
  342. function FindElement(const AName: String): TPasElement; override;
  343. function FindModule(const AName: String): TPasModule; override;
  344. Function HintsToStr(Hints : TPasMemberHints) : String;
  345. // Link tree support
  346. procedure AddLink(const APathName, ALinkTo: String);
  347. function FindAbsoluteLink(const AName: String): String;
  348. function ResolveLink(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String;
  349. function FindLinkedNode(ANode: TDocNode): TDocNode;
  350. Function ShowElement(El : TPasElement) : Boolean; inline;
  351. // Call this before documenting.
  352. Procedure StartDocumenting; virtual;
  353. // Documentation file support
  354. procedure AddDocFile(const AFilename: String;DontTrim:boolean=false);
  355. // Documentation retrieval
  356. function FindDocNode(AElement: TPasElement): TDocNode;
  357. function FindDocNode(ARefModule: TPasModule; const AName: String): TDocNode;
  358. function FindShortDescr(AElement: TPasElement): TDOMElement;
  359. function FindShortDescr(ARefModule: TPasModule; const AName: String): TDOMElement;
  360. function GetExampleFilename(const ExElement: TDOMElement): String;
  361. property RootLinkNode: TLinkNode read FRootLinkNode;
  362. property RootDocNode: TDocNode read FRootDocNode;
  363. Property DocLogLevels : TFPDocLogLevels Read FDocLogLevels Write FDocLogLevels;
  364. Property OnParseUnit : TOnParseUnitEvent Read FOnParseUnit Write FOnParseUnit;
  365. end;
  366. procedure TranslateDocStrings(const Lang: String);
  367. function DumpExceptionCallStack(E: Exception):String;
  368. Function IsLinkNode(Node : TDomNode) : Boolean;
  369. Function IsExampleNode(Example : TDomNode) : Boolean;
  370. // returns true is link is an absolute URI
  371. Function IsLinkAbsolute(ALink: String): boolean;
  372. implementation
  373. uses Gettext, XMLRead;
  374. const
  375. AbsoluteLinkPrefixes : array[0..2] of string = ('/', 'http://', 'ms-its:');
  376. { TObjectList }
  377. destructor TObjectList.Destroy;
  378. var
  379. i: Integer;
  380. begin
  381. for i := 0 to Count - 1 do
  382. TObject(Items[i]).Free;
  383. inherited Destroy;
  384. end;
  385. { TLinkNode }
  386. constructor TLinkNode.Create(const AName, ALink: String);
  387. begin
  388. inherited Create;
  389. FName := AName;
  390. FLink := ALink;
  391. end;
  392. destructor TLinkNode.Destroy;
  393. begin
  394. if Assigned(FirstChild) then
  395. FirstChild.Free;
  396. if Assigned(NextSibling) then
  397. NextSibling.Free;
  398. inherited Destroy;
  399. end;
  400. function TLinkNode.FindChild(const APathName: String): TLinkNode;
  401. var
  402. DotPos: Integer;
  403. ChildName: String;
  404. Child: TLinkNode;
  405. begin
  406. if Length(APathName) = 0 then
  407. Result := Self
  408. else
  409. begin
  410. DotPos := Pos('.', APathName);
  411. if DotPos = 0 then
  412. ChildName := APathName
  413. else
  414. ChildName := Copy(APathName, 1, DotPos - 1);
  415. Child := FirstChild;
  416. while Assigned(Child) do
  417. begin
  418. if CompareText(Child.Name, ChildName) = 0 then
  419. begin
  420. if DotPos = 0 then
  421. Result := Child
  422. else
  423. Result := Child.FindChild(
  424. Copy(APathName, DotPos + 1, Length(APathName)));
  425. exit;
  426. end;
  427. Child := Child.NextSibling;
  428. end;
  429. Result := nil;
  430. end;
  431. end;
  432. function TLinkNode.CreateChildren(const APathName, ALinkTo: String): TLinkNode;
  433. var
  434. DotPos: Integer;
  435. ChildName: String;
  436. Child, LastChild: TLinkNode;
  437. begin
  438. if Length(APathName) = 0 then
  439. Result := Self
  440. else
  441. begin
  442. DotPos := Pos('.', APathName);
  443. if DotPos = 0 then
  444. ChildName := APathName
  445. else
  446. ChildName := Copy(APathName, 1, DotPos - 1);
  447. Child := FirstChild;
  448. LastChild := nil;
  449. while Assigned(Child) do
  450. begin
  451. if CompareText(Child.Name, ChildName) = 0 then
  452. begin
  453. if DotPos = 0 then
  454. Result := Child
  455. else
  456. Result := Child.CreateChildren(
  457. Copy(APathName, DotPos + 1, Length(APathName)), ALinkTo);
  458. exit;
  459. end;
  460. LastChild := Child;
  461. Child := Child.NextSibling;
  462. end;
  463. Result := TLinkNode.Create(ChildName, ALinkTo);
  464. if Assigned(LastChild) then
  465. LastChild.FNextSibling := Result
  466. else
  467. FFirstChild := Result;
  468. end;
  469. end;
  470. { TDocNode }
  471. constructor TDocNode.Create(const AName: String; ANode: TDOMElement);
  472. begin
  473. inherited Create;
  474. FName := AName;
  475. FNode := ANode;
  476. end;
  477. destructor TDocNode.Destroy;
  478. begin
  479. if Assigned(FirstChild) then
  480. FirstChild.Free;
  481. if Assigned(NextSibling) then
  482. NextSibling.Free;
  483. inherited Destroy;
  484. end;
  485. Function TDocNode.IncRefcount : Integer;
  486. begin
  487. Inc(FRefCount);
  488. Result:=FRefCount;
  489. end;
  490. function TDocNode.FindChild(const APathName: String): TDocNode;
  491. var
  492. DotPos: Integer;
  493. ChildName: String;
  494. Child: TDocNode;
  495. begin
  496. if Length(APathName) = 0 then
  497. Result := Self
  498. else
  499. begin
  500. DotPos := Pos('.', APathName);
  501. if DotPos = 0 then
  502. ChildName := APathName
  503. else
  504. ChildName := Copy(APathName, 1, DotPos - 1);
  505. Child := FirstChild;
  506. while Assigned(Child) do
  507. begin
  508. if CompareText(Child.Name, ChildName) = 0 then
  509. begin
  510. if DotPos = 0 then
  511. Result := Child
  512. else
  513. Result := Child.FindChild(
  514. Copy(APathName, DotPos + 1, Length(APathName)));
  515. exit;
  516. end;
  517. Child := Child.NextSibling;
  518. end;
  519. Result := nil;
  520. end;
  521. end;
  522. function TDocNode.CreateChildren(const APathName: String): TDocNode;
  523. var
  524. DotPos: Integer;
  525. ChildName: String;
  526. Child: TDocNode;
  527. begin
  528. if Length(APathName) = 0 then
  529. Result := Self
  530. else
  531. begin
  532. DotPos := Pos('.', APathName);
  533. if DotPos = 0 then
  534. ChildName := APathName
  535. else
  536. ChildName := Copy(APathName, 1, DotPos - 1);
  537. Child := FirstChild;
  538. while Assigned(Child) do
  539. begin
  540. if CompareText(Child.Name, ChildName) = 0 then
  541. begin
  542. if DotPos = 0 then
  543. Result := Child
  544. else
  545. Result := Child.CreateChildren(
  546. Copy(APathName, DotPos + 1, Length(APathName)));
  547. exit;
  548. end;
  549. Child := Child.NextSibling;
  550. end;
  551. // No child found, let's create one
  552. Result := TDocNode.Create(ChildName, nil);
  553. if Assigned(FirstChild) then
  554. begin
  555. Result.FNextSibling := FirstChild;
  556. FFirstChild := Result;
  557. end else
  558. FFirstChild := Result;
  559. if DotPos > 0 then
  560. Result := Result.CreateChildren(
  561. Copy(APathName, DotPos + 1, Length(APathName)));
  562. end;
  563. end;
  564. { TFPDocEngine }
  565. function TFPDocEngine.LogEvent(E: TFPDocLogLevel): Boolean;
  566. begin
  567. Result:=E in FDocLogLevels;
  568. end;
  569. procedure TFPDocEngine.DoLog(const Msg: String);
  570. begin
  571. If Assigned(OnLog) then
  572. OnLog(Self,Msg);
  573. end;
  574. procedure TFPDocEngine.DoLog(const Fmt: String; Args: array of const);
  575. begin
  576. DoLog(Format(Fmt,Args));
  577. end;
  578. constructor TFPDocEngine.Create;
  579. begin
  580. inherited Create;
  581. DescrDocs := TObjectList.Create;
  582. FAlwaysVisible := TStringList.Create;
  583. FAlwaysVisible.CaseSensitive:=True;
  584. DescrDocNames := TStringList.Create;
  585. FRootLinkNode := TLinkNode.Create('', '');
  586. FRootDocNode := TDocNode.Create('', nil);
  587. HidePrivate := True;
  588. InterfaceOnly:=True;
  589. FPackages := TFPList.Create;
  590. end;
  591. destructor TFPDocEngine.Destroy;
  592. var
  593. i: Integer;
  594. begin
  595. for i := 0 to FPackages.Count - 1 do
  596. TPasPackage(FPackages[i]).Release{$IFDEF CheckPasTreeRefCount}('TFPDocEngine.Destroy'){$ENDIF};
  597. FreeAndNil(FRootDocNode);
  598. FreeAndNil(FRootLinkNode);
  599. FreeAndNil(DescrDocNames);
  600. FreeAndNil(DescrDocs);
  601. FreeAndNil(FAlwaysVisible);
  602. FreeAndNil(FPackages);
  603. inherited Destroy;
  604. end;
  605. procedure TFPDocEngine.SetPackageName(const APackageName: String);
  606. begin
  607. ASSERT(not Assigned(Package));
  608. FPackage := TPasPackage(inherited CreateElement(TPasPackage,
  609. '#' + APackageName, nil, '', 0));
  610. FPackages.Add(FPackage);
  611. CurPackageDocNode := RootDocNode.FindChild('#' + APackageName);
  612. If Assigned(CurPackageDocNode) then
  613. CurPackageDocNode.IncRefCount;
  614. end;
  615. procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
  616. var
  617. f: Text;
  618. inheritanceinfo : TStringlist; // contents list of TPasClass with inheritance info
  619. // like this #PackageName.ModuleName.ClassName
  620. tmpLinkPrefix : string;
  621. procedure ReadLinkTree;
  622. var
  623. s: String;
  624. PrevSpaces, ThisSpaces, i, StackIndex: Integer;
  625. CurParent, PrevSibling, NewNode: TLinkNode;
  626. ParentStack, SiblingStack: array[0..7] of TLinkNode;
  627. begin
  628. PrevSpaces := 0;
  629. CurParent := RootLinkNode;
  630. PrevSibling := CurParent.FirstChild;
  631. if assigned(PrevSibling) then
  632. while assigned(PrevSibling.NextSibling) do
  633. PrevSibling := PrevSibling.NextSibling;
  634. StackIndex := 0;
  635. while True do
  636. begin
  637. ReadLn(f, s);
  638. if Length(s) = 0 then
  639. break;
  640. ThisSpaces := 0;
  641. while s[ThisSpaces + 1] = ' ' do
  642. Inc(ThisSpaces);
  643. if ThisSpaces <> PrevSpaces then
  644. begin
  645. if ThisSpaces > PrevSpaces then
  646. begin
  647. { Dive down one level }
  648. ParentStack[StackIndex] := CurParent;
  649. SiblingStack[StackIndex] := PrevSibling;
  650. Inc(StackIndex);
  651. CurParent := PrevSibling;
  652. PrevSibling := nil;
  653. end else
  654. while PrevSpaces > ThisSpaces do
  655. begin
  656. Dec(StackIndex);
  657. CurParent := ParentStack[StackIndex];
  658. PrevSibling := SiblingStack[StackIndex];
  659. Dec(PrevSpaces);
  660. end;
  661. PrevSpaces := ThisSpaces;
  662. end;
  663. i := ThisSpaces + 1;
  664. while s[i] <> ' ' do
  665. Inc(i);
  666. if ALinkPrefix <> '' then
  667. tmpLinkPrefix := ExcludeTrailingPathDelimiter(ALinkPrefix)+'/';
  668. NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
  669. tmpLinkPrefix + Copy(s, i + 1, Length(s)));
  670. if pos(' ',newnode.link)>0 then
  671. writeln(stderr,'Bad format imported node: name="',newnode.name,'" link="',newnode.link,'"');
  672. if Assigned(PrevSibling) then
  673. PrevSibling.FNextSibling := NewNode
  674. else
  675. CurParent.FFirstChild := NewNode;
  676. PrevSibling := NewNode;
  677. end;
  678. end;
  679. function ResolvePackageModule(AName:String;out pkg:TPasPackage;out module:TPasModule;createnew:boolean):String;
  680. var
  681. DotPos, DotPos2, i: Integer;
  682. s: String;
  683. HPackage: TPasPackage;
  684. begin
  685. pkg:=nil; module:=nil; result:='';
  686. // Find or create package
  687. DotPos := Pos('.', AName);
  688. s := Copy(AName, 1, DotPos - 1);
  689. HPackage := nil;
  690. for i := 0 to FPackages.Count - 1 do
  691. if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
  692. begin
  693. HPackage := TPasPackage(FPackages[i]);
  694. break;
  695. end;
  696. if not Assigned(HPackage) then
  697. begin
  698. if not CreateNew then
  699. exit;
  700. HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
  701. '', 0));
  702. FPackages.Add(HPackage);
  703. end;
  704. // Find or create module
  705. DotPos2 := DotPos;
  706. repeat
  707. Inc(DotPos2);
  708. until AName[DotPos2] = '.';
  709. s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
  710. Module := nil;
  711. for i := 0 to HPackage.Modules.Count - 1 do
  712. if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
  713. begin
  714. Module := TPasModule(HPackage.Modules[i]);
  715. break;
  716. end;
  717. if not Assigned(Module) then
  718. begin
  719. if not CreateNew then
  720. exit;
  721. Module := TPasExternalModule.Create(s, HPackage);
  722. Module.InterfaceSection := TInterfaceSection.Create('', Module);
  723. Module.PackageName:= HPackage.Name;
  724. // Module.AddRef{$IFDEF CheckPasTreeRefCount}('ReadContentFile.ResolvePackageModule'){$ENDIF};
  725. HPackage.Modules.Add(Module);
  726. end;
  727. pkg:=hpackage;
  728. result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2);
  729. end;
  730. function SearchInList(clslist:TFPList;s:string):TPasElement;
  731. var i : integer;
  732. ClassEl: TPasElement;
  733. begin
  734. result:=nil;
  735. for i:=0 to clslist.count-1 do
  736. begin
  737. ClassEl := TPasElement(clslist[i]);
  738. if CompareText(ClassEl.Name,s) =0 then
  739. exit(Classel);
  740. end;
  741. end;
  742. function ResolveClassType(AName:String):TPasClassType;
  743. var
  744. pkg : TPasPackage;
  745. module : TPasModule;
  746. s : string;
  747. begin
  748. Result:=nil;
  749. s:=ResolvePackageModule(AName,pkg,module,False);
  750. if not assigned(module) then
  751. exit;
  752. result:=TPasClassType(SearchInList(Module.InterfaceSection.Classes,s));
  753. end;
  754. function ResolveAliasType(AName:String):TPasAliasType;
  755. var
  756. pkg : TPasPackage;
  757. module : TPasModule;
  758. s : string;
  759. begin
  760. Result:=nil;
  761. s:=ResolvePackageModule(AName,pkg,module,False);
  762. if not assigned(module) then
  763. exit;
  764. result:=TPasAliasType(SearchInList(Module.InterfaceSection.Types,s));
  765. if not (result is TPasAliasType) then
  766. result:=nil;
  767. end;
  768. procedure ReadClasses;
  769. function CreateClass(const AName: String;InheritanceStr:String): TPasClassType;
  770. var
  771. s: String;
  772. HPackage: TPasPackage;
  773. Module: TPasModule;
  774. begin
  775. s:= ResolvePackageModule(AName,HPackage,Module,True);
  776. // Create node for class
  777. Result := TPasExternalClassType.Create(s, Module.InterfaceSection);
  778. Result.ObjKind := okClass;
  779. // Result.AddRef{$IFDEF CheckPasTreeRefCount}('ReadContentFile.ResolveAndLinkClass'){$ENDIF};
  780. Module.InterfaceSection.Declarations.Add(Result);
  781. Module.InterfaceSection.Classes.Add(Result);
  782. // defer processing inheritancestr till all classes are loaded.
  783. if inheritancestr<>'' then
  784. InheritanceInfo.AddObject(Inheritancestr,result);
  785. end;
  786. procedure splitalias(var instr:string;out outstr:string);
  787. var i,j:integer;
  788. begin
  789. if length(instr)=0 then exit;
  790. instr:=trim(instr);
  791. i:=pos('(',instr);
  792. if i>0 then
  793. begin
  794. j:=length(instr)-i;
  795. if instr[length(instr)]=')' then
  796. dec(j);
  797. outstr:=copy(instr,i+1,j);
  798. delete(instr,i,j+2);
  799. end
  800. end;
  801. Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType;
  802. begin
  803. result:=TPasClassType(ResolveClassType(clname));
  804. if assigned(result) and not (cls=result) then // save from tobject=implicit tobject
  805. begin
  806. result.addref{$IFDEF CheckPasTreeRefCount}('ReadContentFile.ResolveAndLinkClass'){$ENDIF};
  807. if IsClass then
  808. begin
  809. cls.ancestortype:=result;
  810. // writeln(cls.name, ' has as ancestor ',result.pathname);
  811. end
  812. else
  813. begin
  814. cls.interfaces.add(result);
  815. // writeln(cls.name, ' implements ',result.pathname);
  816. end;
  817. end
  818. else
  819. if cls<>result then
  820. DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]);
  821. end;
  822. function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType;
  823. // create alias clname = alname
  824. var
  825. pkg : TPasPackage;
  826. module : TPasModule;
  827. s : string;
  828. begin
  829. Result:=nil;
  830. s:=ResolvePackageModule(Alname,pkg,module,True);
  831. if not assigned(module) then
  832. exit;
  833. cl2:=TPasClassType(ResolveClassType(alname));
  834. if assigned( cl2) and not (parentclass=cl2) then
  835. begin
  836. result:=ResolveAliasType(clname);
  837. if assigned(result) then
  838. begin
  839. // writeln('found alias ',clname,' (',s,') ',result.classname);
  840. end
  841. else
  842. begin
  843. // writeln('new alias ',clname,' (',s,') ');
  844. cl2.addref{$IFDEF CheckPasTreeRefCount}('ReadContentFile.CreateAliasType'){$ENDIF};
  845. Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0));
  846. module.interfacesection.Declarations.Add(Result);
  847. TPasAliasType(Result).DestType := cl2;
  848. end
  849. end
  850. end;
  851. procedure ProcessInheritanceStrings(inhInfo:TStringList);
  852. var i,j : integer;
  853. cls : TPasClassType;
  854. cls2: TPasClassType;
  855. clname,
  856. alname : string;
  857. inhclass : TStringList;
  858. begin
  859. inhclass:=TStringList.Create;
  860. inhclass.delimiter:=',';
  861. if InhInfo.Count>0 then
  862. for i:=0 to InhInfo.Count-1 do
  863. begin
  864. cls:=TPasClassType(InhInfo.Objects[i]);
  865. inhclass.clear;
  866. inhclass.delimitedtext:=InhInfo[i];
  867. for j:= 0 to inhclass.count-1 do
  868. begin
  869. // writeln('processing',inhclass[j]);
  870. clname:=inhclass[j];
  871. splitalias(clname,alname);
  872. if alname<>'' then // the class//interface we refered to is an alias
  873. begin
  874. // writeln('Found alias pair ',clname,' = ',alname);
  875. if not assigned(CreateAliasType(alname,clname,cls,cls2)) then
  876. DoLog('Warning: creating alias %s for %s failed!',[alname,clname]);
  877. end
  878. else
  879. cls2:=ResolveAndLinkClass(clname,j=0,cls);
  880. end;
  881. end;
  882. inhclass.free;
  883. end;
  884. var
  885. s, Name: String;
  886. CurClass: TPasClassType;
  887. i: Integer;
  888. Member: TPasElement;
  889. begin
  890. inheritanceinfo :=TStringlist.Create;
  891. Try
  892. CurClass := nil;
  893. while True do
  894. begin
  895. ReadLn(f, s);
  896. if Length(s) = 0 then
  897. break;
  898. if s[1] = '#' then
  899. begin
  900. // New class
  901. i := Pos(' ', s);
  902. CurClass := CreateClass(Copy(s, 1, i - 1), copy(s,i+1,length(s)));
  903. end else
  904. begin
  905. i := Pos(' ', s);
  906. if i = 0 then
  907. Name := Copy(s, 3, Length(s))
  908. else
  909. Name := Copy(s, 3, i - 3);
  910. case s[2] of
  911. 'M':
  912. Member := TPasProcedure.Create(Name, CurClass);
  913. 'P':
  914. begin
  915. Member := TPasProperty.Create(Name, CurClass);
  916. if i > 0 then
  917. while i <= Length(s) do
  918. begin
  919. case s[i] of
  920. 'r':
  921. TPasProperty(Member).ReadAccessorName := '<dummy>';
  922. 'w':
  923. TPasProperty(Member).WriteAccessorName := '<dummy>';
  924. 's':
  925. TPasProperty(Member).StoredAccessorName := '<dummy>';
  926. end;
  927. Inc(i);
  928. end;
  929. end;
  930. 'V':
  931. Member := TPasVariable.Create(Name, CurClass);
  932. else
  933. raise Exception.Create('Invalid member type: ' + s[2]);
  934. end;
  935. CurClass.Members.Add(Member);
  936. end;
  937. end;
  938. ProcessInheritanceStrings(Inheritanceinfo);
  939. finally
  940. inheritanceinfo.Free;
  941. end;
  942. end;
  943. var
  944. s: String;
  945. buf : TBufType;
  946. begin
  947. buf:=Default(TBufType);
  948. if not FileExists(AFileName) then
  949. raise EInOutError.Create('File not found: ' + AFileName);
  950. Assign(f, AFilename);
  951. Reset(f);
  952. SetTextBuf(F,Buf,SizeOf(Buf));
  953. while not EOF(f) do
  954. begin
  955. ReadLn(f, s);
  956. if (Length(s) = 0) or (s[1] = '#') then
  957. continue;
  958. if s = ':link tree' then
  959. ReadLinkTree
  960. else if s = ':classes' then
  961. ReadClasses
  962. else
  963. repeat
  964. ReadLn(f, s);
  965. until EOF(f) or (Length(s) = 0);
  966. end;
  967. Close(f);
  968. end;
  969. procedure TFPDocEngine.WriteContentFile(const AFilename: String);
  970. var
  971. ContentFile: Text;
  972. procedure ProcessLinkNode(ALinkNode: TLinkNode; const AIdent: String);
  973. var
  974. ChildNode: TLinkNode;
  975. begin
  976. WriteLn(ContentFile, AIdent, ALinkNode.Name, ' ', ALinkNode.Link);
  977. ChildNode := ALinkNode.FirstChild;
  978. while Assigned(ChildNode) do
  979. begin
  980. ProcessLinkNode(ChildNode, AIdent + ' ');
  981. ChildNode := ChildNode.NextSibling;
  982. end;
  983. end;
  984. function CheckImplicitLink(const s : String):String;
  985. begin
  986. if uppercase(s)='IUNKNOWN' then
  987. Result:='#rtl.System.IUnknown'
  988. else if uppercase(s)='TOBJECT' then
  989. Result:='#rtl.System.TObject'
  990. else
  991. Result:=s;
  992. end;
  993. var
  994. LinkNode: TLinkNode;
  995. i, j, k: Integer;
  996. Module: TPasModule;
  997. Alias : TPasAliasType;
  998. MemberDecl: TPasMembersType;
  999. ClassLikeDecl : TPasClassType;
  1000. Member: TPasElement;
  1001. s: String;
  1002. Buf : TBufType;
  1003. begin
  1004. Buf:=Default(TBufType);
  1005. Assign(ContentFile, AFilename);
  1006. Rewrite(ContentFile);
  1007. SetTextBuf(ContentFile,Buf,SizeOf(Buf));
  1008. try
  1009. WriteLn(ContentFile, '# FPDoc Content File');
  1010. WriteLn(ContentFile, ':link tree');
  1011. LinkNode := RootLinkNode.FirstChild;
  1012. while Assigned(LinkNode) do
  1013. begin
  1014. if LinkNode.Name = Package.Name then
  1015. begin
  1016. ProcessLinkNode(LinkNode, '');
  1017. end;
  1018. LinkNode := LinkNode.NextSibling;
  1019. end;
  1020. if Assigned(Package) then
  1021. begin
  1022. WriteLn(ContentFile);
  1023. WriteLn(ContentFile, ':classes');
  1024. for i := 0 to Package.Modules.Count - 1 do
  1025. begin
  1026. Module := TPasModule(Package.Modules[i]);
  1027. if not assigned(Module.InterfaceSection) then
  1028. continue;
  1029. for j := 0 to Module.InterfaceSection.Classes.Count - 1 do
  1030. begin
  1031. MemberDecl := TPasClassType(Module.InterfaceSection.Classes[j]);
  1032. if MemberDecl is TPasClassType then
  1033. ClassLikeDecl:=MemberDecl as TPasClassType
  1034. else
  1035. ClassLikeDecl:=nil;
  1036. Write(ContentFile, CheckImplicitLink(MemberDecl.PathName), ' ');
  1037. if Assigned(ClassLikeDecl) then
  1038. begin
  1039. if Assigned(ClassLikeDecl.AncestorType) then
  1040. begin
  1041. // simple aliases to class types are coded as "alias(classtype)"
  1042. Write(ContentFile, CheckImplicitLink(ClassLikeDecl.AncestorType.PathName));
  1043. if ClassLikeDecl.AncestorType is TPasAliasType then
  1044. begin
  1045. alias:= TPasAliasType(ClassLikeDecl.AncestorType);
  1046. if assigned(alias.desttype) and (alias.desttype is TPasClassType) then
  1047. write(ContentFile,'(',alias.desttype.PathName,')');
  1048. end;
  1049. end
  1050. else if ClassLikeDecl.ObjKind = okClass then
  1051. Write(ContentFile, '#rtl.System.TObject')
  1052. else if ClassLikeDecl.ObjKind = okInterface then
  1053. Write(ContentFile, '#rtl.System.IUnknown');
  1054. if ClassLikeDecl.Interfaces.Count>0 then
  1055. begin
  1056. for k:=0 to ClassLikeDecl.Interfaces.count-1 do
  1057. begin
  1058. write(contentfile,',',CheckImplicitLink(TPasType(ClassLikeDecl.Interfaces[k]).PathName));
  1059. if TPasElement(ClassLikeDecl.Interfaces[k]) is TPasAliasType then
  1060. begin
  1061. alias:= TPasAliasType(ClassLikeDecl.Interfaces[k]);
  1062. if assigned(alias.desttype) and (alias.desttype is TPasClassType) then
  1063. write(ContentFile,'(',CheckImplicitLink(alias.desttype.PathName),')');
  1064. end;
  1065. end;
  1066. end;
  1067. end;
  1068. writeln(contentfile);
  1069. for k := 0 to MemberDecl.Members.Count - 1 do
  1070. begin
  1071. Member := TPasElement(MemberDecl.Members[k]);
  1072. Write(ContentFile, Chr(Ord(Member.Visibility) + Ord('0')));
  1073. S:='';
  1074. if Member.ClassType = TPasVariable then
  1075. Write(ContentFile, 'V')
  1076. else if Member.ClassType = TPasProperty then
  1077. begin
  1078. Write(ContentFile, 'P');
  1079. if Length(TPasProperty(Member).ReadAccessorName) > 0 then
  1080. s := s + 'r';
  1081. if Length(TPasProperty(Member).WriteAccessorName) > 0 then
  1082. s := s + 'w';
  1083. if Length(TPasProperty(Member).StoredAccessorName) > 0 then
  1084. s := s + 's';
  1085. end else
  1086. Write(ContentFile, 'M'); // Member must be a method
  1087. Write(ContentFile, Member.Name);
  1088. if Length(s) > 0 then
  1089. WriteLn(ContentFile, ' ', s)
  1090. else
  1091. WriteLn(ContentFile);
  1092. end;
  1093. end;
  1094. end;
  1095. end;
  1096. finally
  1097. Close(ContentFile);
  1098. end;
  1099. end;
  1100. function TFPDocEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  1101. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  1102. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  1103. begin
  1104. Result := AClass.Create(AName, AParent);
  1105. Result.Visibility := AVisibility;
  1106. if AClass.InheritsFrom(TPasModule) then
  1107. CurModule := TPasModule(Result);
  1108. Result.SourceFilename := ASourceFilename;
  1109. Result.SourceLinenumber := ASourceLinenumber;
  1110. end;
  1111. function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule
  1112. ) : TPasElement;
  1113. var
  1114. l: TFPList;
  1115. i: Integer;
  1116. begin
  1117. If Assigned(AModule) and Assigned(AModule.InterfaceSection) and
  1118. Assigned(AModule.InterfaceSection.Declarations) then
  1119. begin
  1120. l:=AModule.InterfaceSection.Declarations;
  1121. for i := 0 to l.Count - 1 do
  1122. begin
  1123. Result := TPasElement(l[i]);
  1124. if CompareText(Result.Name, AName) = 0 then
  1125. exit;
  1126. end;
  1127. end;
  1128. Result := nil;
  1129. end;
  1130. function TFPDocEngine.FindElement(const AName: String): TPasElement;
  1131. var
  1132. i: Integer;
  1133. Module: TPasElement;
  1134. begin
  1135. Result := FindInModule( AName, CurModule );
  1136. if not Assigned(Result) and assigned (CurModule.InterfaceSection) then
  1137. for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
  1138. begin
  1139. Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
  1140. if Module.ClassType.InheritsFrom(TPasModule) then
  1141. begin
  1142. Result := FindInModule(AName, TPasModule(Module));
  1143. if Assigned(Result) then
  1144. exit;
  1145. end;
  1146. end;
  1147. end;
  1148. function TFPDocEngine.FindModule(const AName: String): TPasModule;
  1149. function FindInPackage(APackage: TPasPackage): TPasModule;
  1150. var
  1151. i: Integer;
  1152. begin
  1153. for i := 0 to APackage.Modules.Count - 1 do
  1154. begin
  1155. Result := TPasModule(APackage.Modules[i]);
  1156. if CompareText(Result.Name, AName) = 0 then
  1157. exit;
  1158. end;
  1159. Result := nil;
  1160. end;
  1161. var
  1162. i: Integer;
  1163. AInPutLine,OSTarget,CPUTarget : String;
  1164. begin
  1165. Result := FindInPackage(Package);
  1166. if not Assigned(Result) then
  1167. for i := FPackages.Count - 1 downto 0 do
  1168. begin
  1169. if TPasPackage(FPackages[i]) = Package then
  1170. continue;
  1171. Result := FindInPackage(TPasPackage(FPackages[i]));
  1172. if Assigned(Result) then
  1173. exit;
  1174. end;
  1175. if Not Assigned(Result) and Assigned(FOnParseUnit) then
  1176. begin
  1177. FOnParseUnit(Self,AName,AInputLine,OSTarget,CPUTarget);
  1178. If (AInPutLine<>'') then
  1179. Result:=ParseUsedUnit(AName,AInputLine,OSTarget,CPUTarget);
  1180. end;
  1181. end;
  1182. function TFPDocEngine.HintsToStr(Hints: TPasMemberHints): String;
  1183. Var
  1184. H : TPasMemberHint;
  1185. begin
  1186. Result:='';
  1187. For h:=Low(TPasMemberHint) to High(TPasMemberHint) do
  1188. if h in Hints then
  1189. begin
  1190. if (Result<>'') then
  1191. Result:=Result+', ';
  1192. Result:=Result+cPasMemberHint[h]
  1193. end;
  1194. end;
  1195. function TFPDocEngine.ParseUsedUnit(AName, AInputLine, AOSTarget,
  1196. ACPUTarget: String): TPasModule;
  1197. Var
  1198. M : TPasModule;
  1199. begin
  1200. DoLog(SParsingUsedUnit,[AName,AInputLine]);
  1201. M:=CurModule;
  1202. CurModule:=Nil;
  1203. try
  1204. ParseSource(Self,AInputLine,AOSTarget,ACPUTarget,[poUseStreams,poSkipDefaultDefs]);
  1205. Result:=CurModule;
  1206. finally
  1207. CurModule:=M;
  1208. end;
  1209. end;
  1210. procedure TFPDocEngine.AddLink(const APathName, ALinkTo: String);
  1211. begin
  1212. RootLinkNode.CreateChildren(APathName, ALinkTo);
  1213. end;
  1214. function TFPDocEngine.FindAbsoluteLink(const AName: String): String;
  1215. var
  1216. LinkNode: TLinkNode;
  1217. begin
  1218. LinkNode := RootLinkNode.FindChild(AName);
  1219. if Assigned(LinkNode) then
  1220. Result := LinkNode.Link
  1221. else
  1222. SetLength(Result, 0);
  1223. end;
  1224. function TFPDocEngine.ResolveLinkInPackages(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String;
  1225. Var
  1226. ThisPackage: TLinkNode;
  1227. begin
  1228. { Try all packages }
  1229. Result:='';
  1230. ThisPackage:=RootLinkNode.FirstChild;
  1231. while Assigned(ThisPackage) and (Result='') do
  1232. begin
  1233. Result:=ResolveLink(AModule, ThisPackage.Name + '.' + ALinkDest, Strict);
  1234. ThisPackage := ThisPackage.NextSibling;
  1235. end;
  1236. end;
  1237. function TFPDocEngine.ResolveLinkInUsedUnits(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String;
  1238. var
  1239. i: Integer;
  1240. UL: TFPList;
  1241. begin
  1242. Result:='';
  1243. UL:=AModule.InterfaceSection.UsesList;
  1244. I:=UL.Count-1;
  1245. While (Result='') and (I>=0) do
  1246. begin
  1247. Result:=ResolveLinkInPackages(AModule,TPasType(UL[i]).Name+'.'+ALinkDest, strict);
  1248. Dec(I);
  1249. end;
  1250. end;
  1251. function TFPDocEngine.ResolveLink(AModule: TPasModule; const ALinkDest: String; Strict : Boolean = False): String;
  1252. var
  1253. i: Integer;
  1254. begin
  1255. {
  1256. if Assigned(AModule) then
  1257. system.WriteLn('ResolveLink(', AModule.Name, ' - ', ALinkDest, ')... ')
  1258. else
  1259. system.WriteLn('ResolveLink(Nil - ', ALinkDest, ')... ');
  1260. }
  1261. if (ALinkDest='') then
  1262. Exit('');
  1263. if (ALinkDest[1] = '#') then
  1264. Result := FindAbsoluteLink(ALinkDest)
  1265. else if (AModule=Nil) then
  1266. Result:= FindAbsoluteLink(RootLinkNode.FirstChild.Name+'.'+ALinkDest)
  1267. else
  1268. begin
  1269. if Pos(AModule.Name,ALinkDest) = 1 then
  1270. Result := ResolveLink(AModule, AModule.packagename + '.' + ALinkDest, Strict)
  1271. else
  1272. Result := ResolveLink(AModule, AModule.PathName + '.' + ALinkDest, Strict);
  1273. if (Result='') then
  1274. begin
  1275. Result:=ResolveLinkInPackages(AModule,ALinkDest,Strict);
  1276. if (Result='') then
  1277. Result:=ResolveLinkInUsedUnits(Amodule,AlinkDest,Strict);
  1278. end;
  1279. end;
  1280. // Match on parent : class/enumerated/record/module
  1281. if (Result='') and not strict then
  1282. for i := Length(ALinkDest) downto 1 do
  1283. if ALinkDest[i] = '.' then
  1284. begin
  1285. Result := ResolveLink(AModule, Copy(ALinkDest, 1, i - 1), Strict);
  1286. exit;
  1287. end;
  1288. end;
  1289. procedure ReadXMLFileALT(OUT ADoc:TXMLDocument;const AFileName:ansistring);
  1290. var
  1291. Parser: TDOMParser;
  1292. Src: TXMLInputSource;
  1293. FileStream: TStream;
  1294. begin
  1295. ADoc := nil;
  1296. FileStream := TFileStream.Create(AFilename, fmOpenRead+fmShareDenyWrite);
  1297. try
  1298. Parser := TDOMParser.Create; // create a parser object
  1299. try
  1300. Src := TXMLInputSource.Create(FileStream); // and the input source
  1301. src.SystemId:=UTF8Decode(FileNameToUri(AFileName));
  1302. try
  1303. Parser.Options.PreserveWhitespace := True;
  1304. Parser.Parse(Src, ADoc);
  1305. finally
  1306. Src.Free; // cleanup
  1307. end;
  1308. finally
  1309. Parser.Free;
  1310. end;
  1311. finally
  1312. FileStream.Free;
  1313. end;
  1314. end;
  1315. procedure TFPDocEngine.AddDocFile(const AFilename: String;DontTrim:boolean=false);
  1316. Var
  1317. PN : String;
  1318. function ReadNode(OwnerDocNode: TDocNode; Element: TDOMElement): TDocNode;
  1319. var
  1320. Subnode: TDOMNode;
  1321. begin
  1322. if OwnerDocNode = RootDocNode then
  1323. Result := OwnerDocNode.CreateChildren('#' + UTF8Encode(Element['name']))
  1324. else
  1325. Result := OwnerDocNode.CreateChildren(UTF8Encode(Element['name']));
  1326. Result.FNode := Element;
  1327. Result.FLink := UTF8Encode(Element['link']);
  1328. if (Element['alwaysvisible'] = '1') and (Element.NodeName='element') then
  1329. FAlwaysVisible.Add(LowerCase(PN+'.'+TDocNode(OwnerDocNode).Name+'.'+UTF8Encode(Element['name'])));
  1330. Result.FIsSkipped := Element['skip'] = '1';
  1331. Subnode := Element.FirstChild;
  1332. while Assigned(Subnode) do
  1333. begin
  1334. if Subnode.NodeType = ELEMENT_NODE then
  1335. begin
  1336. if Subnode.NodeName = 'short' then
  1337. Result.FShortDescr := TDOMElement(Subnode)
  1338. else if Subnode.NodeName = 'descr' then
  1339. Result.FDescr := TDOMElement(Subnode)
  1340. else if Subnode.NodeName = 'version' then
  1341. begin
  1342. Result.FVersion := TDOMElement(Subnode)
  1343. end
  1344. else if Subnode.NodeName = 'errors' then
  1345. Result.FErrorsDoc := TDOMElement(Subnode)
  1346. else if Subnode.NodeName = 'seealso' then
  1347. Result.FSeeAlso := TDOMElement(Subnode)
  1348. else if (Subnode.NodeName = 'example') and
  1349. not Assigned(Result.FirstExample) then
  1350. Result.FFirstExample := TDOMElement(Subnode)
  1351. else if (Subnode.NodeName = 'notes') then
  1352. Result.FNotes := TDOMElement(Subnode);
  1353. end;
  1354. Subnode := Subnode.NextSibling;
  1355. end;
  1356. end;
  1357. Procedure ReadTopics(TopicNode : TDocNode);
  1358. Var
  1359. SubNode : TDOMNode;
  1360. begin
  1361. SubNode:=TopicNode.FNode.FirstChilD;
  1362. While Assigned(SubNode) do
  1363. begin
  1364. If (SubNode.NodeType=ELEMENT_NODE) and (SubNode.NodeName='topic') then
  1365. With ReadNode(TopicNode,TDomElement(SubNode)) do
  1366. // We could allow recursion here, but we won't, because it doesn't work on paper.
  1367. FTopicNode:=True;
  1368. SubNode:=Subnode.NextSibling;
  1369. end;
  1370. end;
  1371. var
  1372. Node, Subnode, Subsubnode: TDOMNode;
  1373. Doc: TXMLDocument;
  1374. PackageDocNode, TopicNode,ModuleDocNode: TDocNode;
  1375. begin
  1376. if DontTrim then
  1377. ReadXMLFileALT(Doc, AFilename)
  1378. else
  1379. ReadXMLFile(Doc, AFilename);
  1380. DescrDocs.Add(Doc);
  1381. DescrDocNames.Add(AFilename);
  1382. Node := Doc.DocumentElement.FirstChild;
  1383. while Assigned(Node) do
  1384. begin
  1385. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'package') then
  1386. begin
  1387. PackageDocNode := ReadNode(RootDocNode, TDOMElement(Node));
  1388. PackageDocNode.IncRefCount;
  1389. PN:=PackageDocNode.Name;
  1390. // Scan all 'module' elements within this package element
  1391. Subnode := Node.FirstChild;
  1392. while Assigned(Subnode) do
  1393. begin
  1394. if (Subnode.NodeType = ELEMENT_NODE) then
  1395. begin
  1396. If (Subnode.NodeName = 'module') then
  1397. begin
  1398. ModuleDocNode := ReadNode(PackageDocNode, TDOMElement(Subnode));
  1399. // Scan all 'element' elements within this module element
  1400. Subsubnode := Subnode.FirstChild;
  1401. while Assigned(Subsubnode) do
  1402. begin
  1403. if (Subsubnode.NodeType = ELEMENT_NODE) then
  1404. begin
  1405. if (Subsubnode.NodeName = 'element') then
  1406. ReadNode(ModuleDocNode, TDOMElement(Subsubnode))
  1407. else if (SubSubNode.NodeName='topic') then
  1408. begin
  1409. TopicNode:=ReadNode(ModuleDocNode,TDomElement(SubSubNode));
  1410. TopicNode.FTopicNode:=True;
  1411. ReadTopics(TopicNode);
  1412. end;
  1413. end;
  1414. Subsubnode := Subsubnode.NextSibling;
  1415. end;
  1416. end
  1417. else if (SubNode.NodeName='topic') then
  1418. begin
  1419. TopicNode:=ReadNode(PackageDocNode,TDomElement(SubNode));
  1420. TopicNode.FTopicNode:=True;
  1421. ReadTopics(TopicNode);
  1422. end;
  1423. end;
  1424. Subnode := Subnode.NextSibling;
  1425. end;
  1426. end;
  1427. Node := Node.NextSibling;
  1428. end;
  1429. end;
  1430. function TFPDocEngine.FindDocNode(AElement: TPasElement): TDocNode;
  1431. begin
  1432. Result:=Nil;
  1433. If not Assigned(AElement) then
  1434. exit;
  1435. if aElement.CustomData is TDocNode then
  1436. Exit(TDocNode(aElement.CustomData));
  1437. if AElement.InheritsFrom(TPasUnresolvedTypeRef) then
  1438. Result := FindDocNode(AElement.GetModule, AElement.Name)
  1439. else
  1440. begin
  1441. Result := RootDocNode.FindChild(AElement.PathName);
  1442. if (Result=Nil) and (AElement is TPasoperator) then
  1443. Result:=RootDocNode.FindChild(TPasOperator(AElement).OldName(True));
  1444. end;
  1445. if (Result<>Nil) then
  1446. begin
  1447. if aElement.CustomData=Nil then
  1448. aElement.CustomData:=Result;
  1449. end
  1450. else if WarnNoNode and
  1451. (Length(AElement.PathName)>0) and
  1452. (AElement.PathName[1]='#') then
  1453. DoLog(Format('No documentation node found for identifier : %s',[AElement.PathName]));
  1454. end;
  1455. function TFPDocEngine.FindDocNode(ARefModule: TPasModule;
  1456. const AName: String): TDocNode;
  1457. var
  1458. CurPackage: TDocNode;
  1459. UnitList: TFPList;
  1460. i: Integer;
  1461. begin
  1462. if Length(AName) = 0 then
  1463. Result := nil
  1464. else
  1465. begin
  1466. if AName[1] = '#' then
  1467. Result := RootDocNode.FindChild(AName)
  1468. else
  1469. Result := RootDocNode.FindChild(Package.Name + '.' + AName);
  1470. if (not Assigned(Result)) and Assigned(ARefModule) then
  1471. Result := RootDocNode.FindChild(ARefModule.PathName + '.' + AName);
  1472. if (not Assigned(Result)) and (AName[1] <> '#') then
  1473. begin
  1474. CurPackage := RootDocNode.FirstChild;
  1475. while Assigned(CurPackage) do
  1476. begin
  1477. Result := RootDocNode.FindChild(CurPackage.Name + '.' + AName);
  1478. if Assigned(Result) then
  1479. break;
  1480. CurPackage := CurPackage.NextSibling;
  1481. end;
  1482. if not Assigned(Result) and assigned(CurModule.InterfaceSection) then
  1483. begin
  1484. { Okay, then we have to try all imported units of the current module }
  1485. UnitList := CurModule.InterfaceSection.UsesList;
  1486. for i := UnitList.Count - 1 downto 0 do
  1487. begin
  1488. { Try all packages }
  1489. CurPackage := RootDocNode.FirstChild;
  1490. while Assigned(CurPackage) do
  1491. begin
  1492. Result := RootDocNode.FindChild(CurPackage.Name + '.' +
  1493. TPasType(UnitList[i]).Name + '.' + AName);
  1494. if Assigned(Result) then
  1495. break;
  1496. CurPackage := CurPackage.NextSibling;
  1497. end;
  1498. end;
  1499. end;
  1500. end;
  1501. end;
  1502. end;
  1503. function TFPDocEngine.FindShortDescr(AElement: TPasElement): TDOMElement;
  1504. var
  1505. DocNode,N: TDocNode;
  1506. begin
  1507. DocNode := FindDocNode(AElement);
  1508. if Assigned(DocNode) then
  1509. begin
  1510. N:=FindLinkedNode(DocNode);
  1511. If (N<>Nil) then
  1512. DocNode:=N;
  1513. Result := DocNode.ShortDescr;
  1514. end
  1515. else
  1516. Result := nil;
  1517. end;
  1518. function TFPDocEngine.FindLinkedNode(ANode : TDocNode) : TDocNode;
  1519. begin
  1520. If (ANode.Link='') then
  1521. Result:=Nil
  1522. else
  1523. Result:=FindDocNode(CurModule,ANode.Link);
  1524. end;
  1525. function TFPDocEngine.ShowElement(El: TPasElement): Boolean;
  1526. begin
  1527. Case El.Visibility of
  1528. visStrictPrivate,
  1529. visPrivate :
  1530. Result:=Not HidePrivate;
  1531. visStrictProtected,
  1532. visProtected :
  1533. begin
  1534. Result:=Not HideProtected;
  1535. if not Result then
  1536. Result:=FAlwaysVisible.IndexOf(LowerCase(El.PathName))<>-1;
  1537. end
  1538. Else
  1539. Result:=True
  1540. end;
  1541. end;
  1542. procedure TFPDocEngine.StartDocumenting;
  1543. begin
  1544. FAlwaysVisible.Sorted:=True;
  1545. end;
  1546. function TFPDocEngine.FindShortDescr(ARefModule: TPasModule;
  1547. const AName: String): TDOMElement;
  1548. var
  1549. N,DocNode: TDocNode;
  1550. begin
  1551. DocNode := FindDocNode(ARefModule, AName);
  1552. if Assigned(DocNode) then
  1553. begin
  1554. N:=FindLinkedNode(DocNode);
  1555. If (N<>Nil) then
  1556. DocNode:=N;
  1557. Result := DocNode.ShortDescr;
  1558. end
  1559. else
  1560. Result := nil;
  1561. end;
  1562. function TFPDocEngine.GetExampleFilename(const ExElement: TDOMElement): String;
  1563. var
  1564. i: Integer;
  1565. fn : String;
  1566. begin
  1567. Result:='';
  1568. for i := 0 to DescrDocs.Count - 1 do
  1569. begin
  1570. Fn:=UTF8Encode(ExElement['file']);
  1571. if (FN<>'') and (TDOMDocument(DescrDocs[i]) = ExElement.OwnerDocument) then
  1572. begin
  1573. Result := ExtractFilePath(DescrDocNames[i]) + FN;
  1574. if (ExtractFileExt(Result)='') then
  1575. Result:=Result+'.pp';
  1576. end;
  1577. end;
  1578. end;
  1579. { Global helpers }
  1580. procedure TranslateDocStrings(const Lang: String);
  1581. Const
  1582. {$ifdef unix}
  1583. DefDir = '/usr/local/share/locale';
  1584. {$else}
  1585. DefDir = 'intl';
  1586. {$endif}
  1587. var
  1588. mo: TMOFile;
  1589. dir : string;
  1590. begin
  1591. dir:=modir;
  1592. If Dir='' then
  1593. Dir:=DefDir;
  1594. Dir:=IncludeTrailingPathDelimiter(Dir);
  1595. {$IFDEF Unix}
  1596. mo := TMOFile.Create(Format(Dir+'%s/LC_MESSAGES/dglobals.mo', [Lang]));
  1597. {$ELSE}
  1598. mo := TMOFile.Create(Format(Dir+'dglobals.%s.mo', [Lang]));
  1599. {$ENDIF}
  1600. try
  1601. TranslateResourceStrings(mo);
  1602. finally
  1603. mo.Free;
  1604. end;
  1605. end;
  1606. Function IsLinkNode(Node : TDomNode) : Boolean;
  1607. begin
  1608. Result:=Assigned(Node) and (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link');
  1609. end;
  1610. Function IsExampleNode(Example : TDomNode) : Boolean;
  1611. begin
  1612. Result:=Assigned(Example) and (Example.NodeType = ELEMENT_NODE) and (Example.NodeName = 'example')
  1613. end;
  1614. function IsLinkAbsolute(ALink: String): boolean;
  1615. var
  1616. i: integer;
  1617. begin
  1618. Result := false;
  1619. for i := low(AbsoluteLinkPrefixes) to high(AbsoluteLinkPrefixes) do
  1620. if CompareText(AbsoluteLinkPrefixes[i], copy(ALink,1,length(AbsoluteLinkPrefixes[i])))=0 then begin
  1621. Result := true;
  1622. break;
  1623. end;
  1624. end;
  1625. function DumpExceptionCallStack(E: Exception):String;
  1626. var
  1627. I: Integer;
  1628. Frames: PPointer;
  1629. begin
  1630. Result := 'Program exception! ' + LineEnding +
  1631. 'Stacktrace:' + LineEnding + LineEnding;
  1632. if E <> nil then begin
  1633. Result := Result + 'Exception class: ' + E.ClassName + LineEnding +
  1634. 'Message: ' + E.Message + LineEnding;
  1635. end;
  1636. Result := Result + BackTraceStrFunc(ExceptAddr);
  1637. Frames := ExceptFrames;
  1638. for I := 0 to ExceptFrameCount - 1 do
  1639. Result := Result + LineEnding + BackTraceStrFunc(Frames[I]);
  1640. end;
  1641. initialization
  1642. LEOL:=Length(LineEnding);
  1643. end.