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