2
0

dglobals.pp 57 KB

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