2
0

whtmlhlp.pas 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814
  1. {
  2. This file is part of the Free Pascal Integrated Development Environment
  3. Copyright (c) 1999-2000 by Berczi Gabor
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit WHTMLHlp;
  11. interface
  12. uses Objects,WHTML,WAnsi,WHelp,WChmHWrap;
  13. const
  14. extHTML = '.htm';
  15. extHTMLIndex = '.htx';
  16. extCHM = '.chm';
  17. ListIndent = 2;
  18. DefIndent = 4;
  19. MaxTopicLinks = 24000; { maximum number of links on a single HTML page }
  20. type
  21. THTMLSection = (hsNone,hsHeading1,hsHeading2,hsHeading3,hsHeading4,hsHeading5,hsHeading6);
  22. TParagraphAlign = (paLeft,paCenter,paRight);
  23. PTableElement = ^TTableElement;
  24. TTableElement = object(Tobject)
  25. TextBegin,TextEnd, TextLength, NumNL : sw_word;
  26. Alignment : TParagraphAlign;
  27. NextEl : PTableElement;
  28. constructor init(AAlignment : TParagraphAlign);
  29. end;
  30. PTableLine = ^TTableLine;
  31. TTableLine = object(Tobject)
  32. NumElements : sw_word;
  33. Nextline : PTableLine;
  34. FirstEl,LastEl : PTableElement;
  35. constructor Init;
  36. procedure AddElement(PTE : PTableElement);
  37. destructor Done; virtual;
  38. end;
  39. PHTMLTopicRenderer = ^THTMLTopicRenderer;
  40. PTable = ^TTable;
  41. TTable = object(Tobject)
  42. NumLines,NumCols : sw_word;
  43. GlobalOffset,
  44. GlobalTextBegin : sw_word;
  45. WithBorder : boolean;
  46. IsBar : boolean;
  47. FirstLine : PTableLine;
  48. LastLine : PTableLine;
  49. PreviousTable : PTable;
  50. Renderer : PHTMLTopicRenderer;
  51. constructor Init(Previous : PTable);
  52. procedure AddLine(PL : PTableLine);
  53. procedure AddElement(PTE : PTableElement);
  54. procedure TextInsert(Pos : sw_word;const S : string);
  55. procedure FormatTable;
  56. destructor Done; virtual;
  57. end;
  58. THTMLTopicRenderer = object(THTMLParser)
  59. function BuildTopic(P: PTopic; AURL: string; HTMLFile: PTextFile; ATopicLinks: PTopicLinkCollection): boolean;
  60. public
  61. function DocAddTextChar(C: char): boolean; virtual;
  62. procedure DocSoftBreak; virtual;
  63. procedure DocTYPE; virtual;
  64. procedure DocHTML(Entered: boolean); virtual;
  65. procedure DocHEAD(Entered: boolean); virtual;
  66. procedure DocMETA; virtual;
  67. procedure DocTITLE(Entered: boolean); virtual;
  68. procedure DocBODY(Entered: boolean); virtual;
  69. procedure DocAnchor(Entered: boolean); virtual;
  70. procedure DocUnknownTag; virtual;
  71. procedure DocHeading(Level: integer; Entered: boolean); virtual;
  72. procedure DocParagraph(Entered: boolean); virtual;
  73. procedure DocBreak; virtual;
  74. procedure DocImage; virtual;
  75. procedure DocProcessComment(Comment: string); virtual;
  76. procedure DocBold(Entered: boolean); virtual;
  77. procedure DocCite(Entered: boolean); virtual;
  78. procedure DocCode(Entered: boolean); virtual;
  79. procedure DocEmphasized(Entered: boolean); virtual;
  80. procedure DocItalic(Entered: boolean); virtual;
  81. procedure DocKbd(Entered: boolean); virtual;
  82. procedure DocPreformatted(Entered: boolean); virtual;
  83. procedure DocSample(Entered: boolean); virtual;
  84. procedure DocStrong(Entered: boolean); virtual;
  85. procedure DocTeleType(Entered: boolean); virtual;
  86. procedure DocVariable(Entered: boolean); virtual;
  87. procedure DocSpan(Entered: boolean); virtual;
  88. procedure DocList(Entered: boolean); virtual;
  89. procedure DocOrderedList(Entered: boolean); virtual;
  90. procedure DocListItem(Entered: boolean); virtual;
  91. procedure DocDefList(Entered: boolean); virtual;
  92. procedure DocDefTerm(Entered: boolean); virtual;
  93. procedure DocDefExp(Entered: boolean); virtual;
  94. procedure DocTable(Entered: boolean); virtual;
  95. procedure DocTableRow(Entered: boolean); virtual;
  96. procedure DocTableHeaderItem(Entered: boolean); virtual;
  97. procedure DocTableItem(Entered: boolean); virtual;
  98. procedure DocHorizontalRuler; virtual;
  99. function CanonicalizeURL(const Base,Relative:String):string; virtual;
  100. public
  101. function GetSectionColor(Section: THTMLSection; var Color: byte): boolean; virtual;
  102. private
  103. URL: string;
  104. Topic: PTopic;
  105. TopicLinks: PTopicLinkCollection;
  106. TextPtr: sw_word;
  107. InTitle: boolean;
  108. InBody: boolean;
  109. InAnchor: boolean;
  110. InParagraph: boolean;
  111. InPreformatted: boolean;
  112. SuppressOutput: boolean;
  113. SuppressUntil : string;
  114. InDefExp: boolean;
  115. TopicTitle: string;
  116. Indent: integer;
  117. AnyCharsInLine,
  118. LastAnsiLoadFailed: boolean;
  119. CurHeadLevel: integer;
  120. PAlign: TParagraphAlign;
  121. LinkIndexes: array[0..MaxTopicLinks] of sw_integer;
  122. LinkPtr: sw_integer;
  123. LastTextChar: char;
  124. { Anchor: TAnchor;}
  125. { Table stuff }
  126. CurrentTable : PTable;
  127. procedure AddText(const S: string);
  128. procedure AddChar(C: char);
  129. procedure AddCharAt(C: char;AtPtr : sw_word);
  130. function AddTextAt(const S: string;AtPtr : sw_word) : sw_word;
  131. function ComputeTextLength(TStart,TEnd : sw_word) : sw_word;
  132. end;
  133. PCHMTopicRenderer = ^TCHMTopicRenderer;
  134. TCHMTopicRenderer = object(THTMLTopicRenderer)
  135. function CanonicalizeURL(const Base,Relative:String):string; virtual;
  136. end;
  137. PCustomHTMLHelpFile = ^TCustomHTMLHelpFile;
  138. TCustomHTMLHelpFile = object(THelpFile)
  139. constructor Init(AID: word);
  140. destructor Done; virtual;
  141. public
  142. Renderer: PHTMLTopicRenderer;
  143. function GetTopicInfo(T: PTopic) : string; virtual;
  144. function SearchTopic(HelpCtx: THelpCtx): PTopic; virtual;
  145. function ReadTopic(T: PTopic): boolean; virtual;
  146. function FormatLink(const s:String):string; virtual;
  147. private
  148. DefaultFileName: string;
  149. CurFileName: string;
  150. TopicLinks: PTopicLinkCollection;
  151. end;
  152. PHTMLHelpFile = ^THTMLHelpFile;
  153. THTMLHelpFile = object(TCustomHTMLHelpFile)
  154. constructor Init(AFileName: string; AID: word; ATOCEntry: string);
  155. public
  156. function LoadIndex: boolean; virtual;
  157. private
  158. TOCEntry: string;
  159. end;
  160. PCHMHelpFile = ^TCHMHelpFile;
  161. TCHMHelpFile = object(TCustomHTMLHelpFile)
  162. constructor Init(AFileName: string; AID: word);
  163. destructor Done; virtual;
  164. public
  165. function LoadIndex: boolean; virtual;
  166. function ReadTopic(T: PTopic): boolean; virtual;
  167. function GetTopicInfo(T: PTopic) : string; virtual;
  168. function SearchTopic(HelpCtx: THelpCtx): PTopic; virtual;
  169. function FormatLink(const s:String):string; virtual;
  170. private
  171. Chmw: TCHMWrapper;
  172. end;
  173. PHTMLIndexHelpFile = ^THTMLIndexHelpFile;
  174. THTMLIndexHelpFile = object(TCustomHTMLHelpFile)
  175. constructor Init(AFileName: string; AID: word);
  176. function LoadIndex: boolean; virtual;
  177. private
  178. IndexFileName: string;
  179. end;
  180. PHTMLAnsiView = ^THTMLAnsiView;
  181. PHTMLAnsiConsole = ^THTMLAnsiConsole;
  182. THTMLAnsiConsole = Object(TAnsiViewConsole)
  183. MaxX,MaxY : integer;
  184. procedure GotoXY(X,Y: integer); virtual;
  185. end;
  186. THTMLAnsiView = Object(TAnsiView)
  187. private
  188. HTMLOwner : PHTMLTopicRenderer;
  189. HTMLConsole : PHTMLAnsiConsole;
  190. public
  191. constructor Init(AOwner: PHTMLTopicRenderer);
  192. procedure CopyToHTML;
  193. end;
  194. THTMLGetSectionColorProc = function(Section: THTMLSection; var Color: byte): boolean;
  195. function DefHTMLGetSectionColor(Section: THTMLSection; var Color: byte): boolean;
  196. const HTMLGetSectionColor : THTMLGetSectionColorProc = {$ifdef fpc}@{$endif}DefHTMLGetSectionColor;
  197. procedure RegisterHelpType;
  198. implementation
  199. uses
  200. Views,WConsts,WUtils,WViews,WHTMLScn;
  201. constructor TTableElement.init(AAlignment : TParagraphAlign);
  202. begin
  203. Alignment:=AAlignment;
  204. NextEl:=nil;
  205. TextBegin:=0;
  206. TextEnd:=0;
  207. end;
  208. { TTableLine methods }
  209. constructor TTableLine.Init;
  210. begin
  211. NumElements:=0;
  212. NextLine:=nil;
  213. Firstel:=nil;
  214. LastEl:=nil;
  215. end;
  216. procedure TTableLine.AddElement(PTE : PTableElement);
  217. begin
  218. if not assigned(FirstEl) then
  219. FirstEl:=PTE;
  220. if assigned(LastEl) then
  221. LastEl^.NextEl:=PTE;
  222. LastEl:=PTE;
  223. Inc(NumElements);
  224. end;
  225. destructor TTableLine.Done;
  226. begin
  227. LastEl:=FirstEl;
  228. while assigned(LastEl) do
  229. begin
  230. LastEl:=FirstEl^.NextEl;
  231. Dispose(FirstEl,Done);
  232. FirstEl:=LastEl;
  233. end;
  234. inherited Done;
  235. end;
  236. { TTable methods }
  237. constructor TTable.Init(Previous : PTable);
  238. begin
  239. PreviousTable:=Previous;
  240. NumLines:=0;
  241. NumCols:=0;
  242. GlobalOffset:=0;
  243. GlobalTextBegin:=0;
  244. FirstLine:=nil;
  245. LastLine:=nil;
  246. WithBorder:=false;
  247. IsBar:=false;
  248. end;
  249. procedure TTable.AddLine(PL : PTableLine);
  250. begin
  251. If not assigned(FirstLine) then
  252. FirstLine:=PL;
  253. if Assigned(LastLine) then
  254. LastLine^.NextLine:=PL;
  255. LastLine:=PL;
  256. Inc(NumLines);
  257. end;
  258. procedure TTable.AddElement(PTE : PTableElement);
  259. begin
  260. if assigned(LastLine) then
  261. begin
  262. LastLine^.AddElement(PTE);
  263. If LastLine^.NumElements>NumCols then
  264. NumCols:=LastLine^.NumElements;
  265. end;
  266. end;
  267. procedure TTable.TextInsert(Pos : sw_word;const S : string);
  268. var
  269. i : sw_word;
  270. begin
  271. if S='' then
  272. exit;
  273. i:=Renderer^.AddTextAt(S,Pos+GlobalOffset);
  274. GlobalOffset:=GlobalOffset+i;
  275. end;
  276. procedure TTable.FormatTable;
  277. const
  278. MaxCols = 200;
  279. type
  280. TLengthArray = Array [ 1 .. MaxCols] of sw_word;
  281. PLengthArray = ^TLengthArray;
  282. var
  283. ColLengthArray : PLengthArray;
  284. RowSizeArray : PLengthArray;
  285. CurLine : PTableLine;
  286. CurEl : PTableElement;
  287. Align : TParagraphAlign;
  288. TextBegin,TextEnd : sw_word;
  289. i,j,k,Length : sw_word;
  290. begin
  291. { do nothing for single cell tables }
  292. if (NumCols=1) and (NumLines=1) then
  293. exit;
  294. GetMem(ColLengthArray,Sizeof(sw_word)*NumCols);
  295. FillChar(ColLengthArray^,Sizeof(sw_word)*NumCols,#0);
  296. GetMem(RowSizeArray,Sizeof(sw_word)*NumLines);
  297. FillChar(RowSizeArray^,Sizeof(sw_word)*NumLines,#0);
  298. { Compute the largest cell }
  299. CurLine:=FirstLine;
  300. For i:=1 to NumLines do
  301. begin
  302. CurEl:=CurLine^.FirstEl;
  303. RowSizeArray^[i]:=1;
  304. For j:=1 to NumCols do
  305. begin
  306. if not assigned(CurEl) then
  307. break;
  308. Length:=CurEl^.TextLength;
  309. if assigned(CurEl^.NextEl) and
  310. (CurEl^.NextEl^.TextBegin>CurEl^.TextEnd) then
  311. Inc(Length,Renderer^.ComputeTextLength(
  312. CurEl^.NextEl^.TextBegin+GlobalOffset,
  313. CurEl^.TextBegin+GlobalOffset));
  314. if Length>ColLengthArray^[j] then
  315. ColLengthArray^[j]:=Length;
  316. { We need to handle multiline cells... }
  317. if CurEl^.NumNL>=RowSizeArray^[i] then
  318. RowSizeArray^[i]:=CurEl^.NumNL;
  319. { We don't handle multiline cells yet... }
  320. if CurEl^.NumNL>=1 then
  321. begin
  322. for k:=CurEl^.TextBegin+GlobalOffset to
  323. CurEl^.TextEnd+GlobalOffset do
  324. if Renderer^.Topic^.Text^[k]=ord(hscLineBreak) then
  325. Renderer^.Topic^.Text^[k]:=ord(' ');
  326. end;
  327. CurEl:=CurEl^.NextEl;
  328. end;
  329. CurLine:=CurLine^.NextLine;
  330. end;
  331. { Adjust to largest cell }
  332. CurLine:=FirstLine;
  333. TextBegin:=GlobalTextBegin;
  334. If (NumLines>0) and WithBorder then
  335. Begin
  336. TextInsert(TextBegin,#218);
  337. For j:=1 to NumCols do
  338. begin
  339. TextInsert(TextBegin,CharStr(#196,ColLengthArray^[j]));
  340. if j<NumCols then
  341. TextInsert(TextBegin,#194);
  342. end;
  343. TextInsert(TextBegin,#191);
  344. TextInsert(TextBegin,hscLineBreak);
  345. End;
  346. For i:=1 to NumLines do
  347. begin
  348. CurEl:=CurLine^.FirstEl;
  349. For j:=1 to NumCols do
  350. begin
  351. if not assigned(CurEl) then
  352. begin
  353. Length:=0;
  354. Align:=paLeft;
  355. end
  356. else
  357. begin
  358. TextBegin:=CurEl^.TextBegin;
  359. TextEnd:=CurEl^.TextEnd;
  360. {While (TextEnd>TextBegin) and
  361. (Renderer^.Topic^.Text^[TextEnd+GlobalOffset]=ord(hscLineBreak)) do
  362. dec(TextEnd); }
  363. Length:=CurEl^.TextLength;
  364. Align:=CurEl^.Alignment;
  365. end;
  366. if WithBorder then
  367. TextInsert(TextBegin,#179)
  368. else
  369. TextInsert(TextBegin,' ');
  370. if Length<ColLengthArray^[j] then
  371. begin
  372. case Align of
  373. paLeft:
  374. TextInsert(TextEnd,CharStr(' ',ColLengthArray^[j]-Length));
  375. paRight:
  376. TextInsert(TextBegin,CharStr(' ',ColLengthArray^[j]-Length));
  377. paCenter:
  378. begin
  379. TextInsert(TextBegin,CharStr(' ',(ColLengthArray^[j]-Length) div 2));
  380. TextInsert(TextEnd,CharStr(' ',(ColLengthArray^[j]-Length)- ((ColLengthArray^[j]-Length) div 2)));
  381. end;
  382. end;
  383. end;
  384. if Assigned(CurEl) then
  385. CurEl:=CurEl^.NextEl;
  386. end;
  387. if WithBorder then
  388. TextInsert(TextEnd,#179);
  389. //TextInsert(TextEnd,hscLineBreak);
  390. CurLine:=CurLine^.NextLine;
  391. end;
  392. If (NumLines>0) and WithBorder then
  393. Begin
  394. TextInsert(TextEnd,hscLineBreak);
  395. TextInsert(TextEnd,#192);
  396. For j:=1 to NumCols do
  397. begin
  398. TextInsert(TextEnd,CharStr(#196,ColLengthArray^[j]));
  399. if j<NumCols then
  400. TextInsert(TextEnd,#193);
  401. end;
  402. TextInsert(TextEnd,#217);
  403. TextInsert(TextEnd,hscLineBreak);
  404. End;
  405. FreeMem(ColLengthArray,Sizeof(sw_word)*NumCols);
  406. FreeMem(RowSizeArray,Sizeof(sw_word)*NumLines);
  407. end;
  408. destructor TTable.Done;
  409. begin
  410. LastLine:=FirstLine;
  411. while assigned(LastLine) do
  412. begin
  413. LastLine:=FirstLine^.NextLine;
  414. Dispose(FirstLine,Done);
  415. FirstLine:=LastLine;
  416. end;
  417. if Assigned(PreviousTable) then
  418. Inc(PreviousTable^.GlobalOffset,GlobalOffset);
  419. inherited Done;
  420. end;
  421. { THTMLAnsiConsole methods }
  422. procedure THTMLAnsiConsole.GotoXY(X,Y : integer);
  423. begin
  424. if X>MaxX then MaxX:=X-1;
  425. if Y>MaxY then MaxY:=Y-1;
  426. inherited GotoXY(X,Y);
  427. end;
  428. { THTMLAnsiView methods }
  429. constructor THTMLAnsiView.Init(AOwner : PHTMLTopicRenderer);
  430. var
  431. R : TRect;
  432. begin
  433. if not assigned(AOwner) then
  434. fail;
  435. R.Assign(0,0,80,25);
  436. inherited init(R,nil,nil);
  437. HTMLOwner:=AOwner;
  438. HTMLConsole:=New(PHTMLAnsiConsole,Init(@Self));
  439. HTMLConsole^.HighVideo;
  440. Dispose(Console,Done);
  441. Console:=HTMLConsole;
  442. HTMLConsole^.Size.X:=80;
  443. HTMLConsole^.Size.Y:=25;
  444. HTMLConsole^.ClrScr;
  445. HTMLConsole^.MaxX:=-1;
  446. HTMLConsole^.MaxY:=-1;
  447. HTMLConsole^.BoundChecks:=0;
  448. end;
  449. procedure THTMLAnsiView.CopyToHTML;
  450. var
  451. Attr,NewAttr : byte;
  452. c : char;
  453. X,Y,Pos : longint;
  454. begin
  455. Attr:=(Buffer^[1] shr 8);
  456. HTMLOwner^.AddChar(hscLineBreak);
  457. HTMLOwner^.AddText(hscTextAttr+chr(Attr));
  458. for Y:=0 to HTMLConsole^.MaxY-1 do
  459. begin
  460. for X:=0 to HTMLConsole^.MaxX-1 do
  461. begin
  462. Pos:=(Delta.Y*MaxViewWidth)+X+Y*MaxViewWidth;
  463. NewAttr:=(Buffer^[Pos] shr 8);
  464. if NewAttr <> Attr then
  465. begin
  466. Attr:=NewAttr;
  467. HTMLOwner^.AddText(hscTextAttr+chr(Attr));
  468. end;
  469. c:= chr(Buffer^[Pos] and $ff);
  470. if ord(c)>16 then
  471. HTMLOwner^.AddChar(c)
  472. else
  473. begin
  474. HTMLOwner^.AddChar(hscDirect);
  475. HTMLOwner^.AddChar(c);
  476. end;
  477. end;
  478. { Write start of next line in normal color, for correct alignment }
  479. HTMLOwner^.AddChar(hscNormText);
  480. { Force to set attr again at start of next line }
  481. Attr:=0;
  482. HTMLOwner^.AddChar(hscLineBreak);
  483. end;
  484. end;
  485. function DefHTMLGetSectionColor(Section: THTMLSection; var Color: byte): boolean;
  486. begin
  487. Color:=0;
  488. DefHTMLGetSectionColor:=false;
  489. end;
  490. function CharStr(C: char; Count: byte): string;
  491. var S: string;
  492. begin
  493. S[0]:=chr(Count);
  494. if Count>0 then FillChar(S[1],Count,C);
  495. CharStr:=S;
  496. end;
  497. function THTMLTopicRenderer.DocAddTextChar(C: char): boolean;
  498. var Added: boolean;
  499. begin
  500. Added:=false;
  501. if InTitle then
  502. begin
  503. TopicTitle:=TopicTitle+C;
  504. Added:=true;
  505. end
  506. else
  507. if InBody then
  508. begin
  509. if (InPreFormatted) or (C<>#32) or (LastTextChar<>C) then
  510. if (C<>#32) or (AnyCharsInLine=true) or (InPreFormatted=true) then
  511. begin
  512. AddChar(C);
  513. LastTextChar:=C;
  514. Added:=true;
  515. end;
  516. end;
  517. DocAddTextChar:=Added;
  518. end;
  519. procedure THTMLTopicRenderer.DocSoftBreak;
  520. begin
  521. if InPreformatted then DocBreak else
  522. if AnyCharsInLine and not assigned(CurrentTable) then
  523. begin
  524. AddChar(' ');
  525. LastTextChar:=' ';
  526. end;
  527. end;
  528. procedure THTMLTopicRenderer.DocTYPE;
  529. begin
  530. end;
  531. procedure THTMLTopicRenderer.DocHTML(Entered: boolean);
  532. begin
  533. end;
  534. procedure THTMLTopicRenderer.DocHEAD(Entered: boolean);
  535. begin
  536. end;
  537. procedure THTMLTopicRenderer.DocMETA;
  538. begin
  539. end;
  540. procedure THTMLTopicRenderer.DocTITLE(Entered: boolean);
  541. begin
  542. if Entered then
  543. begin
  544. TopicTitle:='';
  545. end
  546. else
  547. begin
  548. { render topic title here }
  549. if TopicTitle<>'' then
  550. begin
  551. AddText(' '+TopicTitle+' Ü'); DocBreak;
  552. AddText(' '+CharStr('ß',length(TopicTitle)+3)); DocBreak;
  553. end;
  554. end;
  555. InTitle:=Entered;
  556. end;
  557. procedure THTMLTopicRenderer.DocBODY(Entered: boolean);
  558. begin
  559. InBody:=Entered;
  560. end;
  561. procedure THTMLTopicRenderer.DocAnchor(Entered: boolean);
  562. var HRef,Name: string;
  563. begin
  564. if Entered and InAnchor then DocAnchor(false);
  565. if Entered then
  566. begin
  567. if DocGetTagParam('HREF',HRef)=false then HRef:='';
  568. if DocGetTagParam('NAME',Name)=false then Name:='';
  569. if {(HRef='') and} (Name='') then
  570. if DocGetTagParam('ID',Name)=false then
  571. Name:='';
  572. if Name<>'' then
  573. begin
  574. Topic^.NamedMarks^.InsertStr(Name);
  575. {$IFDEF WDEBUG}
  576. DebugMessageS({$i %file%},' Adding Name "'+Name+'"',{$i %line%},'1',0,0);
  577. {$endif WDEBUG}
  578. AddChar(hscNamedMark);
  579. end;
  580. if (HRef<>'')then
  581. begin
  582. if (LinkPtr<MaxTopicLinks){ and
  583. not DisableCrossIndexing} then
  584. begin
  585. InAnchor:=true;
  586. AddChar(hscLink);
  587. {$IFDEF WDEBUG}
  588. DebugMessageS({$i %file%},' Adding Link1 "'+HRef+'"'+' "'+url+'"',{$i %line%},'1',0,0);
  589. {$ENDIF WDEBUG}
  590. if pos('#',HRef)=1 then
  591. Href:=NameAndExtOf(GetFilename)+Href;
  592. HRef:=canonicalizeURL(URL,HRef);
  593. LinkIndexes[LinkPtr]:=TopicLinks^.AddItem(HRef);
  594. {$IFDEF WDEBUG}
  595. DebugMessageS({$i %file%},' Adding Link2 "'+HRef+'"',{$i %line%},'1',0,0);
  596. {$ENDIF WDEBUG}
  597. Inc(LinkPtr);
  598. end;
  599. end;
  600. end
  601. else
  602. begin
  603. if InAnchor=true then AddChar(hscLink);
  604. InAnchor:=false;
  605. end;
  606. end;
  607. procedure THTMLTopicRenderer.DocUnknownTag;
  608. begin
  609. {$IFDEF WDEBUG}
  610. DebugMessageS({$i %file%},' Unknown tag "'+TagName+'" params "'+TagParams+'"' ,{$i %line%},'1',0,0);
  611. {$endif WDEBUG}
  612. end;
  613. procedure DecodeAlign(Align: string; var PAlign: TParagraphAlign);
  614. begin
  615. Align:=UpcaseStr(Align);
  616. if Align='LEFT' then PAlign:=paLeft else
  617. if Align='CENTER' then PAlign:=paCenter else
  618. if Align='RIGHT' then PAlign:=paRight;
  619. end;
  620. procedure THTMLTopicRenderer.DocHeading(Level: integer; Entered: boolean);
  621. var Align: string;
  622. C: byte;
  623. SC: THTMLSection;
  624. begin
  625. if Entered then
  626. begin
  627. DocBreak;
  628. CurHeadLevel:=Level;
  629. PAlign:=paLeft;
  630. if DocGetTagParam('ALIGN',Align) then
  631. DecodeAlign(Align,PAlign);
  632. SC:=hsNone;
  633. case Level of
  634. 1: SC:=hsHeading1;
  635. 2: SC:=hsHeading2;
  636. 3: SC:=hsHeading3;
  637. 4: SC:=hsHeading4;
  638. 5: SC:=hsHeading5;
  639. 6: SC:=hsHeading6;
  640. end;
  641. if GetSectionColor(SC,C) then
  642. AddText(hscTextAttr+chr(C));
  643. end
  644. else
  645. begin
  646. AddChar(hscNormText);
  647. CurHeadLevel:=0;
  648. DocBreak;
  649. end;
  650. end;
  651. Function THTMLTopicRenderer.CanonicalizeURL(const Base,Relative:String):string;
  652. // uses info from filesystem (curdir) -> overriden for CHM.
  653. begin
  654. CanonicalizeURL:=CompleteURL(Base,relative);
  655. end;
  656. procedure THTMLTopicRenderer.DocParagraph(Entered: boolean);
  657. var Align: string;
  658. begin
  659. if Entered and InParagraph then DocParagraph(false);
  660. if Entered then
  661. begin
  662. if AnyCharsInLine then DocBreak;
  663. if DocGetTagParam('ALIGN',Align) then
  664. DecodeAlign(Align,PAlign);
  665. end
  666. else
  667. begin
  668. { if AnyCharsInLine then }DocBreak;
  669. PAlign:=paLeft;
  670. end;
  671. InParagraph:=Entered;
  672. end;
  673. procedure THTMLTopicRenderer.DocBreak;
  674. begin
  675. if (CurHeadLevel=1) or (PAlign=paCenter) then
  676. AddChar(hscCenter);
  677. if (PAlign=paRight) then
  678. AddChar(hscRight);
  679. AddChar(hscLineBreak);
  680. if Indent>0 then
  681. AddText(CharStr(#255,Indent)+hscLineStart);
  682. AnyCharsInLine:=false;
  683. end;
  684. procedure THTMLTopicRenderer.DocProcessComment(Comment: string);
  685. var
  686. src,index : string;
  687. begin
  688. if pos('tex4ht:',Comment)=0 then
  689. exit;
  690. {$IFDEF WDEBUG}
  691. DebugMessage(GetFileName,'tex4ht comment "'
  692. +Comment+'"',Line,1);
  693. {$endif WDEBUG}
  694. if SuppressOutput then
  695. begin
  696. if (pos(SuppressUntil,Comment)=0) then
  697. exit
  698. else
  699. begin
  700. {$IFDEF WDEBUG}
  701. DebugMessage(GetFileName,' Found '+SuppressUntil+'comment "'
  702. +Comment+'" SuppressOuput reset to false',Line,1);
  703. {$endif WDEBUG}
  704. SuppressOutput:=false;
  705. SuppressUntil:='';
  706. end;
  707. end;
  708. if (pos('tex4ht:graphics ',Comment)>0) and
  709. LastAnsiLoadFailed then
  710. begin
  711. {$IFDEF WDEBUG}
  712. DebugMessage(GetFileName,' Using tex4ht comment "'
  713. +Comment+'"',Line,1);
  714. {$endif WDEBUG}
  715. { Try again with this info }
  716. TagParams:=Comment;
  717. DocImage;
  718. end;
  719. if (pos('tex4ht:syntaxdiagram ',Comment)>0) then
  720. begin
  721. {$IFDEF WDEBUG}
  722. DebugMessage(GetFileName,' Using tex4ht:syntaxdiagram comment "'
  723. +Comment+'"',Line,1);
  724. {$endif WDEBUG}
  725. { Try again with this info }
  726. TagParams:=Comment;
  727. DocImage;
  728. if not LastAnsiLoadFailed then
  729. begin
  730. SuppressOutput:=true;
  731. SuppressUntil:='tex4ht:endsyntaxdiagram ';
  732. end
  733. end;
  734. if (pos('tex4ht:mysyntdiag ',Comment)>0) then
  735. begin
  736. {$IFDEF WDEBUG}
  737. DebugMessage(GetFileName,' Using tex4ht:mysyntdiag comment "'
  738. +Comment+'"',Line,1);
  739. {$endif WDEBUG}
  740. { Try again with this info }
  741. TagParams:=Comment;
  742. DocGetTagParam('SRC',src);
  743. DocGetTagParam('INDEX',index);
  744. TagParams:='src="../syntax/'+src+'-'+index+'.png"';
  745. DocImage;
  746. if not LastAnsiLoadFailed then
  747. begin
  748. SuppressOutput:=true;
  749. SuppressUntil:='tex4ht:endmysyntdiag ';
  750. end
  751. end;
  752. end;
  753. procedure THTMLTopicRenderer.DocImage;
  754. var Name,Src,Alt,SrcLine: string;
  755. f : text;
  756. attr : byte;
  757. PA : PHTMLAnsiView;
  758. StorePreformatted : boolean;
  759. begin
  760. if SuppressOutput then
  761. exit;
  762. {$IFDEF WDEBUG}
  763. if not DocGetTagParam('NAME',Name) then
  764. Name:='<No name>';
  765. DebugMessage(GetFileName,' Image "'+Name+'"',Line,1);
  766. {$endif WDEBUG}
  767. if DocGetTagParam('SRC',src) then
  768. begin
  769. {$IFDEF WDEBUG}
  770. DebugMessage(GetFileName,' Image source tag "'+Src+'"',Line,1);
  771. {$endif WDEBUG}
  772. if src<>'' then
  773. begin
  774. src:=CompleteURL(URL,src);
  775. { this should be a image file ending by .gif or .jpg...
  776. Try to see if a file with same name and extension .git
  777. exists PM }
  778. src:=DirAndNameOf(src)+'.ans';
  779. {$IFDEF WDEBUG}
  780. DebugMessage(GetFileName,' Trying "'+Src+'"',Line,1);
  781. {$endif WDEBUG}
  782. if not ExistsFile(src) then
  783. begin
  784. DocGetTagParam('SRC',src);
  785. src:=DirAndNameOf(src)+'.ans';
  786. src:=CompleteURL(DirOf(URL)+'../',src);
  787. {$IFDEF WDEBUG}
  788. DebugMessage(GetFileName,' Trying "'+Src+'"',Line,1);
  789. {$endif wDEBUG}
  790. end;
  791. if not ExistsFile(src) then
  792. begin
  793. LastAnsiLoadFailed:=true;
  794. {$IFDEF WDEBUG}
  795. DebugMessage(GetFileName,' "'+Src+'" not found',Line,1);
  796. {$endif WDEBUG}
  797. end
  798. else
  799. begin
  800. PA:=New(PHTMLAnsiView,init(@self));
  801. PA^.LoadFile(src);
  802. LastAnsiLoadFailed:=false;
  803. if AnyCharsInLine then DocBreak;
  804. StorePreformatted:=InPreformatted;
  805. InPreformatted:=true;
  806. {AddText('Image from '+src+hscLineBreak); }
  807. AddChar(hscInImage);
  808. PA^.CopyToHTML;
  809. InPreformatted:=StorePreformatted;
  810. AddChar(hscInImage);
  811. AddChar(hscNormText);
  812. if AnyCharsInLine then DocBreak;
  813. Dispose(PA,Done);
  814. Exit;
  815. end;
  816. { also look for a raw text file without colors }
  817. src:=DirAndNameOf(src)+'.txt';
  818. if not ExistsFile(src) then
  819. begin
  820. LastAnsiLoadFailed:=true;
  821. {$IFDEF WDEBUG}
  822. DebugMessage(GetFileName,' "'+Src+'" not found',Line,1);
  823. {$endif WDEBUG}
  824. end
  825. else
  826. begin
  827. Assign(f,src);
  828. Reset(f);
  829. DocPreformatted(true);
  830. while not eof(f) do
  831. begin
  832. Readln(f,SrcLine);
  833. AddText(SrcLine+hscLineBreak);
  834. end;
  835. Close(f);
  836. LastAnsiLoadFailed:=false;
  837. DocPreformatted(false);
  838. LastAnsiLoadFailed:=false;
  839. Exit;
  840. end;
  841. end;
  842. end;
  843. if DocGetTagParam('ALT',Alt)=false then
  844. begin
  845. DocGetTagParam('SRC',Alt);
  846. if Alt<>'' then
  847. Alt:='Can''t display '+Alt
  848. else
  849. Alt:='IMG';
  850. end;
  851. if Alt<>'' then
  852. begin
  853. StorePreformatted:=InPreformatted;
  854. InPreformatted:=true;
  855. DocGetTagParam('SRC',src);
  856. AddChar(hscInImage);
  857. AddText('[--'+Src+'--'+hscLineBreak);
  858. AddText(Alt+hscLineBreak+'--]');
  859. AddChar(hscInImage);
  860. AddChar(hscNormText);
  861. InPreformatted:=StorePreformatted;
  862. end;
  863. end;
  864. procedure THTMLTopicRenderer.DocBold(Entered: boolean);
  865. begin
  866. end;
  867. procedure THTMLTopicRenderer.DocCite(Entered: boolean);
  868. begin
  869. end;
  870. procedure THTMLTopicRenderer.DocCode(Entered: boolean);
  871. begin
  872. if AnyCharsInLine then DocBreak;
  873. AddText(hscCode);
  874. DocBreak;
  875. end;
  876. procedure THTMLTopicRenderer.DocEmphasized(Entered: boolean);
  877. begin
  878. end;
  879. procedure THTMLTopicRenderer.DocItalic(Entered: boolean);
  880. begin
  881. end;
  882. procedure THTMLTopicRenderer.DocKbd(Entered: boolean);
  883. begin
  884. end;
  885. procedure THTMLTopicRenderer.DocPreformatted(Entered: boolean);
  886. begin
  887. if AnyCharsInLine then DocBreak;
  888. AddText(hscCode);
  889. DocBreak;
  890. InPreformatted:=Entered;
  891. end;
  892. procedure THTMLTopicRenderer.DocSample(Entered: boolean);
  893. begin
  894. end;
  895. procedure THTMLTopicRenderer.DocStrong(Entered: boolean);
  896. begin
  897. end;
  898. procedure THTMLTopicRenderer.DocTeleType(Entered: boolean);
  899. begin
  900. end;
  901. procedure THTMLTopicRenderer.DocVariable(Entered: boolean);
  902. begin
  903. end;
  904. procedure THTMLTopicRenderer.DocSpan(Entered: boolean);
  905. begin
  906. end;
  907. procedure THTMLTopicRenderer.DocList(Entered: boolean);
  908. begin
  909. if Entered then
  910. begin
  911. Inc(Indent,ListIndent);
  912. DocBreak;
  913. end
  914. else
  915. begin
  916. Dec(Indent,ListIndent);
  917. if AnyCharsInLine then DocBreak;
  918. end;
  919. end;
  920. procedure THTMLTopicRenderer.DocOrderedList(Entered: boolean);
  921. begin
  922. DocList(Entered);
  923. end;
  924. procedure THTMLTopicRenderer.DocListItem(Entered: boolean);
  925. begin
  926. if not Entered then
  927. exit;
  928. if AnyCharsInLine then
  929. DocBreak;
  930. AddText('þ'+hscLineStart);
  931. end;
  932. procedure THTMLTopicRenderer.DocDefList(Entered: boolean);
  933. begin
  934. if Entered then
  935. begin
  936. { if LastChar<>hscLineBreak then DocBreak;}
  937. end
  938. else
  939. begin
  940. if AnyCharsInLine then DocBreak;
  941. InDefExp:=false;
  942. end;
  943. end;
  944. procedure THTMLTopicRenderer.DocDefTerm(Entered: boolean);
  945. begin
  946. if not Entered then
  947. exit;
  948. DocBreak;
  949. end;
  950. procedure THTMLTopicRenderer.DocDefExp(Entered: boolean);
  951. begin
  952. if not Entered then
  953. begin
  954. if InDefExp then
  955. Dec(Indent,DefIndent);
  956. InDefExp:=false;
  957. end
  958. else
  959. begin
  960. if not InDefExp then
  961. Inc(Indent,DefIndent);
  962. InDefExp:=true;
  963. DocBreak;
  964. end;
  965. end;
  966. procedure THTMLTopicRenderer.DocTable(Entered: boolean);
  967. var
  968. ATable : PTable;
  969. Param : String;
  970. begin
  971. if AnyCharsInLine then
  972. begin
  973. AddChar(hscLineBreak);
  974. AnyCharsInLine:=false;
  975. end;
  976. if Entered then
  977. begin
  978. DocBreak;
  979. New(ATable,Init(CurrentTable));
  980. CurrentTable:=ATable;
  981. CurrentTable^.Renderer:=@Self;
  982. if DocGetTagParam('BORDER',Param) then
  983. if Param<>'0' then
  984. CurrentTable^.WithBorder:=true;
  985. if DocGetTagParam('CLASS',Param) then
  986. if Param='bar' then
  987. CurrentTable^.IsBar:=true;
  988. end
  989. else
  990. begin
  991. CurrentTable^.FormatTable;
  992. ATable:=CurrentTable;
  993. CurrentTable:=ATable^.PreviousTable;
  994. Dispose(ATable,Done);
  995. end;
  996. end;
  997. procedure THTMLTopicRenderer.DocTableRow(Entered: boolean);
  998. var
  999. ATableLine : PTableLine;
  1000. begin
  1001. if AnyCharsInLine or
  1002. (assigned(CurrentTable) and
  1003. assigned(CurrentTable^.FirstLine)) then
  1004. begin
  1005. AddChar(hscLineBreak);
  1006. AnyCharsInLine:=false;
  1007. end;
  1008. if Entered then
  1009. begin
  1010. New(ATableLine,Init);
  1011. if CurrentTable^.GlobalTextBegin=0 then
  1012. CurrentTable^.GlobalTextBegin:=TextPtr;
  1013. CurrentTable^.AddLine(ATableLine);
  1014. end;
  1015. end;
  1016. procedure THTMLTopicRenderer.DocTableItem(Entered: boolean);
  1017. var
  1018. Align : String;
  1019. i : sw_word;
  1020. NewEl : PTableElement;
  1021. PAlignEl : TParagraphAlign;
  1022. begin
  1023. if Entered then
  1024. begin
  1025. if assigned(CurrentTable^.LastLine) and Assigned(CurrentTable^.LastLine^.LastEl) and
  1026. (CurrentTable^.LastLine^.LastEl^.TextEnd=sw_word(-1)) then
  1027. begin
  1028. NewEl:=CurrentTable^.LastLine^.LastEl;
  1029. NewEl^.TextEnd:=TextPtr;
  1030. NewEl^.TextLength:=ComputeTextLength(
  1031. NewEl^.TextBegin+CurrentTable^.GlobalOffset,
  1032. TextPtr+CurrentTable^.GlobalOffset);
  1033. end;
  1034. PAlignEl:=paLeft;
  1035. if DocGetTagParam('ALIGN',Align) then
  1036. DecodeAlign(Align,PAlignEl);
  1037. New(NewEl,Init(PAlignEl));
  1038. CurrentTable^.AddElement(NewEl);
  1039. NewEl^.TextBegin:=TextPtr;
  1040. NewEl^.TextEnd:=sw_word(-1);
  1041. { AddText(' - ');}
  1042. end
  1043. else
  1044. begin
  1045. NewEl:=CurrentTable^.LastLine^.LastEl;
  1046. NewEl^.TextEnd:=TextPtr;
  1047. NewEl^.TextLength:=ComputeTextLength(
  1048. NewEl^.TextBegin+CurrentTable^.GlobalOffset,
  1049. TextPtr+CurrentTable^.GlobalOffset);
  1050. NewEl^.NumNL:=0;
  1051. for i:=NewEl^.TextBegin to TextPtr do
  1052. begin
  1053. if Topic^.Text^[i]=ord(hscLineBreak) then
  1054. inc(NewEl^.NumNL);
  1055. end;
  1056. end;
  1057. end;
  1058. procedure THTMLTopicRenderer.DocTableHeaderItem(Entered: boolean);
  1059. begin
  1060. { Treat as a normal item }
  1061. DocTableItem(Entered);
  1062. end;
  1063. procedure THTMLTopicRenderer.DocHorizontalRuler;
  1064. var OAlign: TParagraphAlign;
  1065. begin
  1066. OAlign:=PAlign;
  1067. if AnyCharsInLine then DocBreak;
  1068. PAlign:=paCenter;
  1069. DocAddText(' '+CharStr('Ä',60)+' ');
  1070. DocBreak;
  1071. PAlign:=OAlign;
  1072. end;
  1073. procedure THTMLTopicRenderer.AddChar(C: char);
  1074. begin
  1075. if (Topic=nil) or (TextPtr=MaxBytes) or SuppressOutput then Exit;
  1076. Topic^.Text^[TextPtr]:=ord(C);
  1077. Inc(TextPtr);
  1078. if (C>#15) and ((C<>' ') or (InPreFormatted=true)) then
  1079. AnyCharsInLine:=true;
  1080. end;
  1081. procedure THTMLTopicRenderer.AddCharAt(C: char;AtPtr : sw_word);
  1082. begin
  1083. if (Topic=nil) or (TextPtr=MaxBytes) or SuppressOutput then Exit;
  1084. if AtPtr>TextPtr then
  1085. AtPtr:=TextPtr
  1086. else
  1087. begin
  1088. Move(Topic^.Text^[AtPtr],Topic^.Text^[AtPtr+1],TextPtr-AtPtr);
  1089. end;
  1090. Topic^.Text^[AtPtr]:=ord(C);
  1091. Inc(TextPtr);
  1092. end;
  1093. procedure THTMLTopicRenderer.AddText(const S: string);
  1094. var I: sw_integer;
  1095. begin
  1096. for I:=1 to length(S) do
  1097. AddChar(S[I]);
  1098. end;
  1099. function THTMLTopicRenderer.ComputeTextLength(TStart,TEnd : sw_word) : sw_word;
  1100. var I,tot: sw_integer;
  1101. begin
  1102. tot:=0;
  1103. i:=TStart;
  1104. while i<= TEnd-1 do
  1105. begin
  1106. inc(tot);
  1107. case chr(Topic^.Text^[i]) of
  1108. hscLink,hscCode,
  1109. hscCenter,hscRight,
  1110. hscNamedMark,hscNormText :
  1111. Dec(tot);{ Do not increase tot }
  1112. hscDirect:
  1113. begin
  1114. Inc(i); { Skip next }
  1115. //Inc(tot);
  1116. end;
  1117. hscTextAttr,
  1118. hscTextColor:
  1119. begin
  1120. Inc(i);
  1121. Dec(tot);
  1122. end;
  1123. end;
  1124. inc(i);
  1125. end;
  1126. ComputeTextLength:=tot;
  1127. end;
  1128. function THTMLTopicRenderer.AddTextAt(const S: String;AtPtr : sw_word) : sw_word;
  1129. var
  1130. i,slen,len : sw_word;
  1131. begin
  1132. if (Topic=nil) or (TextPtr>=MaxBytes) or SuppressOutput then Exit;
  1133. slen:=length(s);
  1134. if TextPtr+slen>=MaxBytes then
  1135. slen:=MaxBytes-TextPtr;
  1136. if AtPtr>TextPtr then
  1137. AtPtr:=TextPtr
  1138. else
  1139. begin
  1140. len:=TextPtr-AtPtr;
  1141. Move(Topic^.Text^[AtPtr],Topic^.Text^[AtPtr+slen],len);
  1142. end;
  1143. for i:=1 to slen do
  1144. begin
  1145. Topic^.Text^[AtPtr]:=ord(S[i]);
  1146. Inc(TextPtr);
  1147. inc(AtPtr);
  1148. if (TextPtr=MaxBytes) then Exit;
  1149. end;
  1150. AddTextAt:=slen;
  1151. end;
  1152. function THTMLTopicRenderer.GetSectionColor(Section: THTMLSection; var Color: byte): boolean;
  1153. begin
  1154. GetSectionColor:=HTMLGetSectionColor(Section,Color);
  1155. end;
  1156. function THTMLTopicRenderer.BuildTopic(P: PTopic; AURL: string; HTMLFile: PTextFile;
  1157. ATopicLinks: PTopicLinkCollection): boolean;
  1158. var OK: boolean;
  1159. TP: pointer;
  1160. I: sw_integer;
  1161. begin
  1162. URL:=AURL;
  1163. Topic:=P; TopicLinks:=ATopicLinks;
  1164. OK:=Assigned(Topic) and Assigned(HTMLFile) and Assigned(TopicLinks);
  1165. if OK then
  1166. begin
  1167. if (Topic^.TextSize<>0) and Assigned(Topic^.Text) then
  1168. begin
  1169. FreeMem(Topic^.Text,Topic^.TextSize);
  1170. Topic^.TextSize:=0; Topic^.Text:=nil;
  1171. end;
  1172. Topic^.TextSize:=MaxHelpTopicSize;
  1173. GetMem(Topic^.Text,Topic^.TextSize);
  1174. TopicTitle:='';
  1175. InTitle:=false; InBody:={false}true; InAnchor:=false;
  1176. InParagraph:=false; InPreformatted:=false;
  1177. Indent:=0; CurHeadLevel:=0;
  1178. PAlign:=paLeft;
  1179. TextPtr:=0; LinkPtr:=0;
  1180. AnyCharsInLine:=false;
  1181. LastTextChar:=#0;
  1182. SuppressUntil:='';
  1183. SuppressOutput:=false;
  1184. OK:=Process(HTMLFile);
  1185. if OK then
  1186. begin
  1187. { --- topic links --- }
  1188. if (Topic^.Links<>nil) and (Topic^.LinkSize>0) then
  1189. begin
  1190. FreeMem(Topic^.Links,Topic^.LinkSize);
  1191. Topic^.Links:=nil; Topic^.LinkCount:=0;
  1192. end;
  1193. Topic^.LinkCount:=LinkPtr{TopicLinks^.Count}; { <- eeeeeek! }
  1194. GetMem(Topic^.Links,Topic^.LinkSize);
  1195. if Topic^.LinkCount>0 then { FP causes numeric RTE 215 without this }
  1196. for I:=0 to Min(Topic^.LinkCount-1,High(LinkIndexes)-1) do
  1197. begin
  1198. {$IFDEF WDEBUG}
  1199. DebugMessageS({$i %file%},' Indexing links ('+inttostr(i)+')'+topiclinks^.at(linkindexes[i])^,{$i %line%},'1',0,0);
  1200. {$endif WDEBUG}
  1201. Topic^.Links^[I].FileID:=Topic^.FileID;
  1202. Topic^.Links^[I].Context:=EncodeHTMLCtx(Topic^.FileID,LinkIndexes[I]+1);
  1203. end;
  1204. { --- topic text --- }
  1205. GetMem(TP,TextPtr);
  1206. Move(Topic^.Text^,TP^,TextPtr);
  1207. FreeMem(Topic^.Text,Topic^.TextSize);
  1208. Topic^.Text:=TP; Topic^.TextSize:=TextPtr;
  1209. end
  1210. else
  1211. begin
  1212. DisposeTopic(Topic);
  1213. Topic:=nil;
  1214. end;
  1215. end;
  1216. BuildTopic:=OK;
  1217. end;
  1218. Function TCHMTopicRenderer.CanonicalizeURL(const Base,Relative:String):string;
  1219. begin
  1220. if copy(relative,1,7)<>'ms-its:' then
  1221. CanonicalizeUrl:=combinepaths(relative,base)
  1222. else
  1223. CanonicalizeUrl:=relative;
  1224. end;
  1225. constructor TCustomHTMLHelpFile.Init(AID: word);
  1226. begin
  1227. inherited Init(AID);
  1228. New(Renderer, Init);
  1229. New(TopicLinks, Init(50,500));
  1230. end;
  1231. function TCustomHTMLHelpFile.SearchTopic(HelpCtx: THelpCtx): PTopic;
  1232. function MatchCtx(P: PTopic): boolean;
  1233. begin
  1234. MatchCtx:=P^.HelpCtx=HelpCtx;
  1235. end;
  1236. var FileID,LinkNo: word;
  1237. P: PTopic;
  1238. FName: string;
  1239. begin
  1240. DecodeHTMLCtx(HelpCtx,FileID,LinkNo);
  1241. if (HelpCtx<>0) and (FileID<>ID) then P:=nil else
  1242. if (FileID=ID) and (LinkNo>TopicLinks^.Count) then P:=nil else
  1243. begin
  1244. P:=Topics^.FirstThat(@MatchCtx);
  1245. if P=nil then
  1246. begin
  1247. if LinkNo=0 then
  1248. FName:=DefaultFileName
  1249. else
  1250. FName:=TopicLinks^.At(LinkNo-1)^;
  1251. P:=NewTopic(ID,HelpCtx,0,FName,nil,0);
  1252. Topics^.Insert(P);
  1253. end;
  1254. end;
  1255. SearchTopic:=P;
  1256. end;
  1257. function TCustomHTMLHelpFile.FormatLink(const s:String):string;
  1258. begin
  1259. formatlink:=formatpath(s);
  1260. end;
  1261. function TCustomHTMLHelpFile.GetTopicInfo(T: PTopic) : string;
  1262. var OK: boolean;
  1263. Name: string;
  1264. Link,Bookmark: string;
  1265. P: sw_integer;
  1266. begin
  1267. Bookmark:='';
  1268. OK:=T<>nil;
  1269. if OK then
  1270. begin
  1271. if T^.HelpCtx=0 then
  1272. begin
  1273. Name:=DefaultFileName;
  1274. P:=0;
  1275. end
  1276. else
  1277. begin
  1278. Link:=TopicLinks^.At((T^.HelpCtx and $ffff)-1)^;
  1279. {$IFDEF WDEBUG}
  1280. DebugMessageS({$i %file%},'(Topicinfo) Link before formatpath "'+link+'"',{$i %line%},'1',0,0);
  1281. {$ENDIF WDEBUG}
  1282. Link:=FormatLink(Link);
  1283. {$IFDEF WDEBUG}
  1284. DebugMessageS({$i %file%},'(Topicinfo) Link after formatpath "'+link+'"',{$i %line%},'1',0,0);
  1285. {$ENDIF WDEBUG}
  1286. P:=Pos('#',Link);
  1287. if P>0 then
  1288. begin
  1289. Bookmark:=copy(Link,P+1,length(Link));
  1290. Link:=copy(Link,1,P-1);
  1291. end;
  1292. { if CurFileName='' then Name:=Link else
  1293. Name:=CompletePath(CurFileName,Link);}
  1294. Name:=Link;
  1295. end;
  1296. end;
  1297. GetTopicInfo:=Name+'#'+BookMark;
  1298. end;
  1299. function TCustomHTMLHelpFile.ReadTopic(T: PTopic): boolean;
  1300. var OK: boolean;
  1301. HTMLFile: PMemoryTextFile;
  1302. Name: string;
  1303. Link,Bookmark: string;
  1304. P: sw_integer;
  1305. begin
  1306. Bookmark:='';
  1307. OK:=T<>nil;
  1308. if OK then
  1309. begin
  1310. if T^.HelpCtx=0 then
  1311. begin
  1312. Name:=DefaultFileName;
  1313. P:=0;
  1314. end
  1315. else
  1316. begin
  1317. Link:=TopicLinks^.At((T^.HelpCtx and $ffff)-1)^;
  1318. {$IFDEF WDEBUG}
  1319. DebugMessageS({$i %file%},'(ReadTopic) Link before formatpath "'+link+'"',{$i %line%},'1',0,0);
  1320. {$ENDIF WDEBUG}
  1321. Link:=FormatPath(Link);
  1322. {$IFDEF WDEBUG}
  1323. DebugMessageS({$i %file%},'(ReadTopic) Link before formatpath "'+link+'"',{$i %line%},'1',0,0);
  1324. {$ENDIF WDEBUG}
  1325. P:=Pos('#',Link);
  1326. if P>0 then
  1327. begin
  1328. Bookmark:=copy(Link,P+1,length(Link));
  1329. Link:=copy(Link,1,P-1);
  1330. end;
  1331. { if CurFileName='' then Name:=Link else
  1332. Name:=CompletePath(CurFileName,Link);}
  1333. Name:=Link;
  1334. end;
  1335. HTMLFile:=nil;
  1336. if Name<>'' then
  1337. HTMLFile:=New(PDOSTextFile, Init(Name));
  1338. if (HTMLFile=nil) and (CurFileName<>'') then
  1339. begin
  1340. Name:=CurFileName;
  1341. HTMLFile:=New(PDOSTextFile, Init(Name));
  1342. end;
  1343. if (HTMLFile=nil) then
  1344. begin
  1345. {$IFDEF WDEBUG}
  1346. DebugMessageS({$i %file%},'(ReadTopic) Filename not known: "'+link+'"',{$i %line%},'1',0,0);
  1347. {$ENDIF WDEBUG}
  1348. end;
  1349. if (p>1) and (HTMLFile=nil) then
  1350. begin
  1351. {$IFDEF WDEBUG}
  1352. if p>0 then
  1353. DebugMessage(Name,Link+'#'+Bookmark+' not found',1,1)
  1354. else
  1355. DebugMessage(Name,Link+' not found',1,1);
  1356. {$endif WDEBUG}
  1357. New(HTMLFile, Init);
  1358. HTMLFile^.AddLine('<HEAD><TITLE>'+msg_pagenotavailable+'</TITLE></HEAD>');
  1359. HTMLFile^.AddLine(
  1360. '<BODY>'+
  1361. FormatStrStr(msg_cantaccessurl,Name)+'<br><br>'+
  1362. '</BODY>');
  1363. end;
  1364. OK:=Renderer^.BuildTopic(T,Name,HTMLFile,TopicLinks);
  1365. if OK then
  1366. CurFileName:=Name
  1367. else
  1368. begin
  1369. {$IFDEF WDEBUG}
  1370. if p>0 then
  1371. DebugMessage(Name,Link+'#'+Bookmark+' not found',1,1)
  1372. else
  1373. DebugMessage(Name,Link+' not found',1,1);
  1374. {$endif WDEBUG}
  1375. end;
  1376. if HTMLFile<>nil then Dispose(HTMLFile, Done);
  1377. if BookMark='' then
  1378. T^.StartNamedMark:=0
  1379. else
  1380. begin
  1381. P:=T^.GetNamedMarkIndex(BookMark);
  1382. {$IFDEF WDEBUG}
  1383. if p=-1 then
  1384. DebugMessage(Name,Link+'#'+Bookmark+' bookmark not found',1,1);
  1385. {$endif WDEBUG}
  1386. T^.StartNamedMark:=P+1;
  1387. end;
  1388. end;
  1389. ReadTopic:=OK;
  1390. end;
  1391. destructor TCustomHTMLHelpFile.Done;
  1392. begin
  1393. inherited Done;
  1394. if Renderer<>nil then Dispose(Renderer, Done);
  1395. if TopicLinks<>nil then Dispose(TopicLinks, Done);
  1396. end;
  1397. constructor THTMLHelpFile.Init(AFileName: string; AID: word; ATOCEntry: string);
  1398. begin
  1399. if inherited Init(AID)=false then Fail;
  1400. DefaultFileName:=AFileName; TOCEntry:=ATOCEntry;
  1401. if DefaultFileName='' then
  1402. begin
  1403. Done;
  1404. Fail;
  1405. end;
  1406. end;
  1407. function THTMLHelpFile.LoadIndex: boolean;
  1408. begin
  1409. IndexEntries^.Insert(NewIndexEntry(TOCEntry,ID,0));
  1410. LoadIndex:=true;
  1411. end;
  1412. constructor THTMLIndexHelpFile.Init(AFileName: string; AID: word);
  1413. begin
  1414. inherited Init(AID);
  1415. IndexFileName:=AFileName;
  1416. end;
  1417. function THTMLIndexHelpFile.LoadIndex: boolean;
  1418. function FormatAlias(Alias: string): string;
  1419. begin
  1420. if Assigned(HelpFacility) then
  1421. if length(Alias)>HelpFacility^.IndexTabSize-4 then
  1422. Alias:=Trim(copy(Alias,1,HelpFacility^.IndexTabSize-4-2))+'..';
  1423. FormatAlias:=Alias;
  1424. end;
  1425. (*procedure AddDoc(P: PHTMLLinkScanDocument);
  1426. var I: sw_integer;
  1427. TLI: THelpCtx;
  1428. begin
  1429. for I:=1 to P^.GetAliasCount do
  1430. begin
  1431. TLI:=TopicLinks^.AddItem(P^.GetName);
  1432. TLI:=EncodeHTMLCtx(ID,TLI+1);
  1433. IndexEntries^.Insert(NewIndexEntry(FormatAlias(P^.GetAlias(I-1)),ID,TLI));
  1434. end;
  1435. end;*)
  1436. var S: PBufStream;
  1437. LS: PHTMLLinkScanner;
  1438. OK: boolean;
  1439. TLI: THelpCtx;
  1440. I,J: sw_integer;
  1441. begin
  1442. New(S, Init(IndexFileName,stOpenRead,4096));
  1443. OK:=Assigned(S);
  1444. if OK then
  1445. begin
  1446. New(LS, LoadDocuments(S^));
  1447. OK:=Assigned(LS);
  1448. if OK then
  1449. begin
  1450. LS^.SetBaseDir(DirOf(IndexFileName));
  1451. for I:=0 to LS^.GetDocumentCount-1 do
  1452. begin
  1453. TLI:=TopicLinks^.AddItem(LS^.GetDocumentURL(I));
  1454. TLI:=EncodeHTMLCtx(ID,TLI+1);
  1455. for J:=0 to LS^.GetDocumentAliasCount(I)-1 do
  1456. IndexEntries^.Insert(NewIndexEntry(
  1457. FormatAlias(LS^.GetDocumentAlias(I,J)),ID,TLI));
  1458. end;
  1459. Dispose(LS, Done);
  1460. end;
  1461. Dispose(S, Done);
  1462. end;
  1463. LoadIndex:=OK;
  1464. end;
  1465. constructor TChmHelpFile.Init(AFileName: string; AID: word);
  1466. begin
  1467. if inherited Init(AID)=false then
  1468. Fail;
  1469. Dispose(renderer,done);
  1470. renderer:=New(PCHMTopicRenderer, Init);
  1471. DefaultFileName:=AFileName;
  1472. if (DefaultFileName='') or not ExistsFile(DefaultFilename) then
  1473. begin
  1474. Done;
  1475. Fail;
  1476. end
  1477. else
  1478. chmw:=TCHMWrapper.Create(DefaultFileName);
  1479. end;
  1480. function TChmHelpFile.LoadIndex: boolean;
  1481. begin
  1482. loadindex:=false;
  1483. if assigned(chmw) then
  1484. loadindex:=chmw.loadindex(id,TopicLinks,IndexEntries,helpfacility);
  1485. end;
  1486. function TCHMHelpFile.FormatLink(const s:String):string;
  1487. // do not reformat for chms, we assume them internally consistent.
  1488. begin
  1489. formatlink:=s;
  1490. end;
  1491. function TChmHelpFile.SearchTopic(HelpCtx: THelpCtx): PTopic;
  1492. function MatchCtx(P: PTopic): boolean;
  1493. begin
  1494. MatchCtx:=P^.HelpCtx=HelpCtx;
  1495. end;
  1496. var FileID,LinkNo: word;
  1497. P: PTopic;
  1498. FName: string;
  1499. begin
  1500. DecodeHTMLCtx(HelpCtx,FileID,LinkNo);
  1501. if (HelpCtx<>0) and (FileID<>ID) then P:=nil else
  1502. if (FileID=ID) and (LinkNo>TopicLinks^.Count) then P:=nil else
  1503. begin
  1504. P:=Topics^.FirstThat(@MatchCtx);
  1505. if P=nil then
  1506. begin
  1507. if LinkNo=0 then
  1508. FName:=DefaultFileName
  1509. else
  1510. FName:=TopicLinks^.At(LinkNo-1)^;
  1511. P:=NewTopic(ID,HelpCtx,0,FName,nil,0);
  1512. Topics^.Insert(P);
  1513. end;
  1514. end;
  1515. SearchTopic:=P;
  1516. end;
  1517. function TChmHelpFile.GetTopicInfo(T: PTopic) : string;
  1518. var OK: boolean;
  1519. Name: string;
  1520. Link,Bookmark: string;
  1521. P: sw_integer;
  1522. begin
  1523. Bookmark:='';
  1524. OK:=T<>nil;
  1525. if OK then
  1526. begin
  1527. if T^.HelpCtx=0 then
  1528. begin
  1529. Name:=DefaultFileName;
  1530. P:=0;
  1531. end
  1532. else
  1533. begin
  1534. Link:=TopicLinks^.At((T^.HelpCtx and $ffff)-1)^;
  1535. Link:=FormatPath(Link);
  1536. {$IFDEF WDEBUG}
  1537. DebugMessageS({$i %file%},' Looking for "'+Link+'"',{$i %line%},'1',0,0);
  1538. {$endif WDEBUG}
  1539. P:=Pos('#',Link);
  1540. if P>0 then
  1541. begin
  1542. Bookmark:=copy(Link,P+1,length(Link));
  1543. Link:=copy(Link,1,P-1);
  1544. end;
  1545. { if CurFileName='' then Name:=Link else
  1546. Name:=CompletePath(CurFileName,Link);}
  1547. Name:=Link;
  1548. end;
  1549. end;
  1550. GetTopicInfo:=Name+'#'+BookMark;
  1551. end;
  1552. function TChmHelpFile.ReadTopic(T: PTopic): boolean;
  1553. var OK: boolean;
  1554. HTMLFile: PMemoryTextFile;
  1555. Name: string;
  1556. Link,Bookmark: string;
  1557. P: sw_integer;
  1558. begin
  1559. Bookmark:='';
  1560. OK:=T<>nil;
  1561. if OK then
  1562. begin
  1563. if T^.HelpCtx=0 then
  1564. begin
  1565. Name:=DefaultFileName;
  1566. P:=0;
  1567. end
  1568. else
  1569. begin
  1570. Link:=TopicLinks^.At((T^.HelpCtx and $ffff)-1)^;
  1571. {$IFDEF WDEBUG}
  1572. DebugMessageS({$i %file%},' Looking for "'+Link+'"',{$i %line%},'1',0,0);
  1573. {$endif WDEBUG}
  1574. Link:=FormatLink(Link);
  1575. {$IFDEF WDEBUG}
  1576. DebugMessageS({$i %file%},' Looking for (after formatlink) "'+Link+'"',{$i %line%},'1',0,0);
  1577. {$endif WDEBUG}
  1578. P:=Pos('#',Link);
  1579. if P>0 then
  1580. begin
  1581. Bookmark:=copy(Link,P+1,length(Link));
  1582. Link:=copy(Link,1,P-1);
  1583. end;
  1584. { if CurFileName='' then Name:=Link else
  1585. Name:=CompletePath(CurFileName,Link);}
  1586. Name:=Link;
  1587. end;
  1588. HTMLFile:=nil;
  1589. if Name<>'' then
  1590. HTMLFile:=chmw.gettopic(name);
  1591. if (HTMLFile=nil) and (CurFileName<>'') then
  1592. begin
  1593. Name:=CurFileName;
  1594. HTMLFile:=chmw.gettopic(name);
  1595. end;
  1596. if (HTMLFile=nil) then
  1597. begin
  1598. {$IFDEF WDEBUG}
  1599. DebugMessage(Link,' filename not known :(',1,1);
  1600. {$endif WDEBUG}
  1601. end;
  1602. if (p>1) and (HTMLFile=nil) then
  1603. begin
  1604. {$IFDEF WDEBUG}
  1605. if p>0 then
  1606. DebugMessage(Name,Link+'#'+Bookmark+' not found',1,1)
  1607. else
  1608. DebugMessage(Name,Link+' not found',1,1);
  1609. {$endif WDEBUG}
  1610. New(HTMLFile, Init);
  1611. HTMLFile^.AddLine('<HEAD><TITLE>'+msg_pagenotavailable+'</TITLE></HEAD>');
  1612. HTMLFile^.AddLine(
  1613. '<BODY>'+
  1614. FormatStrStr(msg_cantaccessurl,Name)+'<br><br>'+
  1615. '</BODY>');
  1616. end;
  1617. OK:=Renderer^.BuildTopic(T,Name,HTMLFile,TopicLinks);
  1618. if OK then
  1619. CurFileName:=Name
  1620. else
  1621. begin
  1622. {$IFDEF WDEBUG}
  1623. if p>0 then
  1624. DebugMessage(Name,Link+'#'+Bookmark+' not found',1,1)
  1625. else
  1626. DebugMessage(Name,Link+' not found',1,1);
  1627. {$endif WDEBUG}
  1628. end;
  1629. if HTMLFile<>nil then Dispose(HTMLFile, Done);
  1630. if BookMark='' then
  1631. T^.StartNamedMark:=0
  1632. else
  1633. begin
  1634. P:=T^.GetNamedMarkIndex(BookMark);
  1635. {$IFDEF WDEBUG}
  1636. if p=-1 then
  1637. DebugMessage(Name,Link+'#'+Bookmark+' bookmark not found',1,1);
  1638. {$endif WDEBUG}
  1639. T^.StartNamedMark:=P+1;
  1640. end;
  1641. end;
  1642. ReadTopic:=OK;
  1643. end;
  1644. destructor TChmHelpFile.done;
  1645. begin
  1646. if assigned(chmw) then
  1647. chmw.free;
  1648. inherited Done;
  1649. end;
  1650. function CreateProcHTML(const FileName,Param: string;Index : longint): PHelpFile;
  1651. var H: PHelpFile;
  1652. begin
  1653. H:=nil;
  1654. if CompareText(copy(ExtOf(FileName),1,length(extHTML)),extHTML)=0 then
  1655. H:=New(PHTMLHelpFile, Init(FileName,Index,Param));
  1656. CreateProcHTML:=H;
  1657. end;
  1658. function CreateProcCHM(const FileName,Param: string;Index : longint): PHelpFile;
  1659. var H: PHelpFile;
  1660. begin
  1661. H:=nil;
  1662. if CompareText(copy(ExtOf(FileName),1,length(extCHM)),extCHM)=0 then
  1663. H:=New(PCHMHelpFile, Init(FileName,Index));
  1664. CreateProcCHM:=H;
  1665. end;
  1666. function CreateProcHTMLIndex(const FileName,Param: string;Index : longint): PHelpFile;
  1667. var H: PHelpFile;
  1668. begin
  1669. H:=nil;
  1670. if CompareText(ExtOf(FileName),extHTMLIndex)=0 then
  1671. H:=New(PHTMLIndexHelpFile, Init(FileName,Index));
  1672. CreateProcHTMLIndex:=H;
  1673. end;
  1674. procedure RegisterHelpType;
  1675. begin
  1676. RegisterHelpFileType({$ifdef FPC}@{$endif}CreateProcHTML);
  1677. RegisterHelpFileType({$ifdef FPC}@{$endif}CreateProcHTMLIndex);
  1678. RegisterHelpFileType({$ifdef FPC}@{$endif}CreateProcCHM);
  1679. end;
  1680. END.