whelp.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by Berczi Gabor
  5. Help support & Borland OA .HLP reader objects and routines
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$R-}
  13. unit WHelp;
  14. interface
  15. uses
  16. {$ifdef Win32}
  17. { placed here to avoid TRect to be found in windows unit
  18. for win32 target whereas its found in objects unit for other targets PM }
  19. windows,
  20. {$endif Win32}
  21. Objects,
  22. WUtils;
  23. const
  24. MinFormatVersion = $04; { was $34 }
  25. TP55FormatVersion = $04;
  26. TP70FormatVersion = $34;
  27. Signature = '$*$* &&&&$*$'#0;
  28. ncRawChar = $F;
  29. ncRepChar = $E;
  30. oa_rtFileHeader = Byte ($0);
  31. oa_rtContext = Byte ($1);
  32. oa_rtText = Byte ($2);
  33. oa_rtKeyWord = Byte ($3);
  34. oa_rtIndex = Byte ($4);
  35. oa_rtCompression = Byte ($5);
  36. oa_rtIndexTags = Byte ($6);
  37. ctNone = $00;
  38. ctNibble = $02;
  39. hscLineBreak = #0;
  40. hscLink = #2;
  41. hscLineStart = #3;
  42. hscCode = #5;
  43. hscCenter = #10;
  44. hscRight = #11;
  45. hscNamedMark = #12;
  46. hscTextAttr = #13;
  47. hscTextColor = #14;
  48. hscNormText = #15;
  49. type
  50. FileStamp = array [0..32] of char; {+ null terminator + $1A }
  51. FileSignature = array [0..12] of char; {+ null terminator }
  52. THelpCtx = longint;
  53. THLPVersion = packed record
  54. FormatVersion : byte;
  55. TextVersion : byte;
  56. end;
  57. THLPRecordHeader = packed record
  58. RecType : byte; {TPRecType}
  59. RecLength : word;
  60. end;
  61. THLPContextPos = packed record
  62. LoW: word;
  63. HiB: byte;
  64. end;
  65. THLPContexts = packed record
  66. ContextCount : word;
  67. Contexts : array[0..0] of THLPContextPos;
  68. end;
  69. THLPFileHeader = packed record
  70. Options : word;
  71. MainIndexScreen : word;
  72. MaxScreenSize : word;
  73. Height : byte;
  74. Width : byte;
  75. LeftMargin : byte;
  76. end;
  77. THLPCompression = packed record
  78. CompType : byte;
  79. CharTable : array [0..13] of byte;
  80. end;
  81. THLPIndexDescriptor = packed record
  82. LengthCode : byte;
  83. UniqueChars : array [0..0] of byte;
  84. Context : word;
  85. end;
  86. THLPIndexTable = packed record
  87. IndexCount : word;
  88. Entries : record end;
  89. end;
  90. THLPKeywordDescriptor = packed record
  91. KwContext : word;
  92. end;
  93. THLPKeyWordRecord = packed record
  94. UpContext : word;
  95. DownContext : word;
  96. KeyWordCount : word;
  97. Keywords : array[0..0] of THLPKeywordDescriptor;
  98. end;
  99. THLPKeywordDescriptor55 = packed record
  100. PosY : byte;
  101. StartX : byte;
  102. EndX : byte;
  103. Dunno : array[0..1] of word;
  104. KwContext : word;
  105. end;
  106. THLPKeyWordRecord55 = packed record
  107. UpContext : word;
  108. DownContext : word;
  109. KeyWordCount : byte;
  110. Keywords : array[0..0] of THLPKeywordDescriptor55;
  111. end;
  112. TRecord = packed record
  113. SClass : word;
  114. Size : word;
  115. Data : pointer;
  116. end;
  117. PIndexEntry = ^TIndexEntry;
  118. TIndexEntry = packed record
  119. Tag : PString;
  120. HelpCtx : THelpCtx;
  121. FileID : word;
  122. end;
  123. PKeywordDescriptor = ^TKeywordDescriptor;
  124. TKeywordDescriptor = packed record
  125. FileID : word;
  126. Context : THelpCtx;
  127. end;
  128. PKeywordDescriptors = ^TKeywordDescriptors;
  129. TKeywordDescriptors = array[0..MaxBytes div sizeof(TKeywordDescriptor)-1] of TKeywordDescriptor;
  130. PTopic = ^TTopic;
  131. TTopic = object
  132. HelpCtx : THelpCtx;
  133. FileOfs : longint;
  134. TextSize : sw_word;
  135. Text : PByteArray;
  136. LinkCount : sw_word;
  137. Links : PKeywordDescriptors;
  138. LastAccess : longint;
  139. FileID : word;
  140. Param : PString;
  141. StartNamedMark: integer;
  142. NamedMarks : PUnsortedStringCollection;
  143. function LinkSize: sw_word;
  144. function GetNamedMarkIndex(const MarkName: string): sw_integer;
  145. end;
  146. PTopicCollection = ^TTopicCollection;
  147. TTopicCollection = object(TSortedCollection)
  148. function At(Index: sw_Integer): PTopic;
  149. procedure FreeItem(Item: Pointer); virtual;
  150. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  151. function SearchTopic(AHelpCtx: THelpCtx): PTopic;
  152. end;
  153. PIndexEntryCollection = ^TIndexEntryCollection;
  154. TIndexEntryCollection = object(TSortedCollection)
  155. function At(Index: Sw_Integer): PIndexEntry;
  156. procedure FreeItem(Item: Pointer); virtual;
  157. function Compare(Key1, Key2: Pointer): Sw_Integer; virtual;
  158. end;
  159. PUnsortedIndexEntryCollection = ^TUnsortedIndexEntryCollection;
  160. TUnsortedIndexEntryCollection = object(TCollection)
  161. function At(Index: Sw_Integer): PIndexEntry;
  162. procedure FreeItem(Item: Pointer); virtual;
  163. end;
  164. PHelpFile = ^THelpFile;
  165. THelpFile = object(TObject)
  166. ID : word;
  167. Topics : PTopicCollection;
  168. IndexEntries : PUnsortedIndexEntryCollection;
  169. constructor Init(AID: word);
  170. function LoadTopic(HelpCtx: THelpCtx): PTopic; virtual;
  171. procedure AddTopic(HelpCtx: THelpCtx; Pos: longint; const Param: string);
  172. procedure AddIndexEntry(const Text: string; AHelpCtx: THelpCtx);
  173. destructor Done; virtual;
  174. public
  175. function LoadIndex: boolean; virtual;
  176. function SearchTopic(HelpCtx: THelpCtx): PTopic; virtual;
  177. function ReadTopic(T: PTopic): boolean; virtual;
  178. private
  179. procedure MaintainTopicCache;
  180. end;
  181. POAHelpFile = ^TOAHelpFile;
  182. TOAHelpFile = object(THelpFile)
  183. Version : THLPVersion;
  184. Header : THLPFileHeader;
  185. Compression : THLPCompression;
  186. constructor Init(AFileName: string; AID: word);
  187. destructor Done; virtual;
  188. public
  189. function LoadIndex: boolean; virtual;
  190. function ReadTopic(T: PTopic): boolean; virtual;
  191. public { protected }
  192. F: PStream;
  193. TopicsRead : boolean;
  194. IndexTableRead : boolean;
  195. CompressionRead: boolean;
  196. IndexTagsRead : boolean;
  197. IndexTagsPos : longint;
  198. IndexTablePos : longint;
  199. function ReadHeader: boolean;
  200. function ReadTopics: boolean;
  201. function ReadIndexTable: boolean;
  202. function ReadCompression: boolean;
  203. function ReadIndexTags: boolean;
  204. function ReadRecord(var R: TRecord; ReadData: boolean): boolean;
  205. end;
  206. PHelpFileCollection = PCollection;
  207. PHelpFacility = ^THelpFacility;
  208. THelpFacility = object(TObject)
  209. HelpFiles: PHelpFileCollection;
  210. IndexTabSize: sw_integer;
  211. constructor Init;
  212. function AddOAHelpFile(const FileName: string): boolean;
  213. function AddHTMLHelpFile(const FileName, TOCEntry: string): boolean;
  214. function AddNGHelpFile(const FileName: string): boolean;
  215. function AddWinHelpFile(const FileName: string): boolean;
  216. function AddHTMLIndexHelpFile(const FileName: string): boolean;
  217. function LoadTopic(SourceFileID: word; Context: THelpCtx): PTopic; virtual;
  218. function TopicSearch(Keyword: string; var FileID: word; var Context: THelpCtx): boolean; virtual;
  219. function BuildIndexTopic: PTopic; virtual;
  220. destructor Done; virtual;
  221. private
  222. LastID: word;
  223. function SearchFile(ID: byte): PHelpFile;
  224. function SearchTopicInHelpFile(F: PHelpFile; Context: THelpCtx): PTopic;
  225. function SearchTopicOwner(SourceFileID: word; Context: THelpCtx): PHelpFile;
  226. function AddFile(H: PHelpFile): boolean;
  227. end;
  228. const TopicCacheSize : sw_integer = 10;
  229. HelpStreamBufSize : sw_integer = 4096;
  230. HelpFacility : PHelpFacility = nil;
  231. MaxHelpTopicSize : sw_word = {$ifdef FPC}3*65520{$else}65520{$endif};
  232. function NewTopic(FileID: byte; HelpCtx: THelpCtx; Pos: longint; Param: string): PTopic;
  233. procedure DisposeTopic(P: PTopic);
  234. procedure RenderTopic(Lines: PUnsortedStringCollection; T: PTopic);
  235. procedure BuildTopic(Lines: PUnsortedStringCollection; T: PTopic);
  236. procedure AddLinkToTopic(T: PTopic; AFileID: word; ACtx: THelpCtx);
  237. function NewIndexEntry(Tag: string; FileID: word; HelpCtx: THelpCtx): PIndexEntry;
  238. procedure DisposeIndexEntry(P: PIndexEntry);
  239. procedure DisposeRecord(var R: TRecord);
  240. implementation
  241. uses
  242. {$ifdef Linux}
  243. linux,
  244. {$endif Linux}
  245. WConsts,WHTMLHlp,WNGHelp,WWinHelp;
  246. Function GetDosTicks:longint; { returns ticks at 18.2 Hz, just like DOS }
  247. {$IFDEF LINUX}
  248. var
  249. tv : TimeVal;
  250. tz : TimeZone;
  251. begin
  252. GetTimeOfDay(tv); {Timezone no longer used?}
  253. GetDosTicks:=((tv.Sec mod 86400) div 60)*1092+((tv.Sec mod 60)*1000000+tv.USec) div 54945;
  254. end;
  255. {$endif Linux}
  256. {$ifdef Win32}
  257. begin
  258. GetDosTicks:=(Windows.GetTickCount*5484) div 100;
  259. end;
  260. {$endif Win32}
  261. {$ifdef go32v2}
  262. begin
  263. GetDosTicks:=MemL[$40:$6c];
  264. end;
  265. {$endif go32v2}
  266. {$ifdef TP}
  267. begin
  268. GetDosTicks:=MemL[$40:$6c];
  269. end;
  270. {$endif go32v2}
  271. procedure DisposeRecord(var R: TRecord);
  272. begin
  273. with R do
  274. if (Size>0) and (Data<>nil) then FreeMem(Data, Size);
  275. FillChar(R, SizeOf(R), 0);
  276. end;
  277. function NewTopic(FileID: byte; HelpCtx: THelpCtx; Pos: longint; Param: string): PTopic;
  278. var P: PTopic;
  279. begin
  280. New(P); FillChar(P^,SizeOf(P^), 0);
  281. P^.HelpCtx:=HelpCtx; P^.FileOfs:=Pos; P^.FileID:=FileID;
  282. P^.Param:=NewStr(Param);
  283. New(P^.NamedMarks, Init(100,100));
  284. NewTopic:=P;
  285. end;
  286. procedure DisposeTopic(P: PTopic);
  287. begin
  288. if P<>nil then
  289. begin
  290. if (P^.TextSize>0) and (P^.Text<>nil) then
  291. FreeMem(P^.Text,P^.TextSize);
  292. P^.Text:=nil;
  293. if (P^.LinkCount>0) and (P^.Links<>nil) then
  294. FreeMem(P^.Links,P^.LinkSize);
  295. P^.Links:=nil;
  296. if P^.Param<>nil then DisposeStr(P^.Param); P^.Param:=nil;
  297. if Assigned(P^.NamedMarks) then Dispose(P^.NamedMarks, Done); P^.NamedMarks:=nil;
  298. Dispose(P);
  299. end;
  300. end;
  301. function CloneTopic(T: PTopic): PTopic;
  302. var NT: PTopic;
  303. procedure CloneMark(P: PString); {$ifndef FPC}far;{$endif}
  304. begin
  305. NT^.NamedMarks^.InsertStr(GetStr(P));
  306. end;
  307. begin
  308. New(NT); Move(T^,NT^,SizeOf(NT^));
  309. if NT^.Text<>nil then
  310. begin GetMem(NT^.Text,NT^.TextSize); Move(T^.Text^,NT^.Text^,NT^.TextSize); end;
  311. if NT^.Links<>nil then
  312. begin GetMem(NT^.Links,NT^.LinkSize); Move(T^.Links^,NT^.Links^,NT^.LinkSize); end;
  313. if NT^.Param<>nil then
  314. NT^.Param:=NewStr(T^.Param^);
  315. if Assigned(T^.NamedMarks) then
  316. begin
  317. New(NT^.NamedMarks, Init(T^.NamedMarks^.Count,10));
  318. T^.NamedMarks^.ForEach(@CloneMark);
  319. end;
  320. CloneTopic:=NT;
  321. end;
  322. procedure RenderTopic(Lines: PUnsortedStringCollection; T: PTopic);
  323. var Size,CurPtr,I,MSize: sw_word;
  324. S: string;
  325. begin
  326. CurPtr:=0;
  327. for I:=0 to Lines^.Count-1 do
  328. begin
  329. S:=GetStr(Lines^.At(I));
  330. Size:=length(S)+1;
  331. Inc(CurPtr,Size);
  332. end;
  333. Size:=CurPtr;
  334. T^.TextSize:=Size; GetMem(T^.Text,T^.TextSize);
  335. CurPtr:=0;
  336. for I:=0 to Lines^.Count-1 do
  337. begin
  338. S:=GetStr(Lines^.At(I)); Size:=length(S); MSize:=Size;
  339. if CurPtr+Size>=T^.TextSize then
  340. MSize:=T^.TextSize-CurPtr;
  341. Move(S[1],PByteArray(T^.Text)^[CurPtr],MSize);
  342. if MSize<>Size then
  343. Break;
  344. Inc(CurPtr,Size);
  345. PByteArray(T^.Text)^[CurPtr]:=ord(hscLineBreak);
  346. Inc(CurPtr);
  347. if CurPtr>=T^.TextSize then Break;
  348. end;
  349. end;
  350. procedure BuildTopic(Lines: PUnsortedStringCollection; T: PTopic);
  351. var Size,CurPtr,I,MSize: sw_word;
  352. S: string;
  353. begin
  354. CurPtr:=0;
  355. for I:=0 to Lines^.Count-1 do
  356. begin
  357. S:=GetStr(Lines^.At(I));
  358. Size:=length(S);
  359. Inc(CurPtr,Size);
  360. end;
  361. Size:=CurPtr;
  362. T^.TextSize:=Size; GetMem(T^.Text,T^.TextSize);
  363. CurPtr:=0;
  364. for I:=0 to Lines^.Count-1 do
  365. begin
  366. S:=GetStr(Lines^.At(I)); Size:=length(S); MSize:=Size;
  367. if Size>0 then
  368. begin
  369. if CurPtr+Size>=T^.TextSize then
  370. MSize:=T^.TextSize-CurPtr;
  371. Move(S[1],PByteArray(T^.Text)^[CurPtr],MSize);
  372. if MSize<>Size then
  373. Break;
  374. Inc(CurPtr,Size);
  375. end;
  376. if CurPtr>=T^.TextSize then Break;
  377. end;
  378. end;
  379. procedure AddLinkToTopic(T: PTopic; AFileID: word; ACtx: THelpCtx);
  380. var NewSize: word;
  381. NewPtr: pointer;
  382. begin
  383. NewSize:=longint(T^.LinkCount+1)*sizeof(T^.Links^[0]);
  384. GetMem(NewPtr,NewSize);
  385. if Assigned(T^.Links) then
  386. begin
  387. Move(T^.Links^,NewPtr^,T^.LinkSize);
  388. FreeMem(T^.Links,T^.LinkSize);
  389. end;
  390. T^.Links:=NewPtr;
  391. with T^.Links^[T^.LinkCount] do
  392. begin
  393. FileID:=AFileID;
  394. Context:=ACtx;
  395. end;
  396. Inc(T^.LinkCount);
  397. end;
  398. function NewIndexEntry(Tag: string; FileID: word; HelpCtx: THelpCtx): PIndexEntry;
  399. var P: PIndexEntry;
  400. begin
  401. New(P); FillChar(P^,SizeOf(P^), 0);
  402. P^.Tag:=NewStr(Tag); P^.FileID:=FileID; P^.HelpCtx:=HelpCtx;
  403. NewIndexEntry:=P;
  404. end;
  405. procedure DisposeIndexEntry(P: PIndexEntry);
  406. begin
  407. if P<>nil then
  408. begin
  409. if P^.Tag<>nil then DisposeStr(P^.Tag);
  410. Dispose(P);
  411. end;
  412. end;
  413. function TTopic.LinkSize: sw_word;
  414. begin
  415. LinkSize:=LinkCount*SizeOf(Links^[0]);
  416. end;
  417. function TTopic.GetNamedMarkIndex(const MarkName: string): sw_integer;
  418. var I,Index: sw_integer;
  419. begin
  420. Index:=-1;
  421. if Assigned(NamedMarks) then
  422. for I:=0 to NamedMarks^.Count-1 do
  423. if CompareText(GetStr(NamedMarks^.At(I)),MarkName)=0 then
  424. begin
  425. Index:=I;
  426. Break;
  427. end;
  428. GetNamedMarkIndex:=Index;
  429. end;
  430. function TTopicCollection.At(Index: sw_Integer): PTopic;
  431. begin
  432. At:=inherited At(Index);
  433. end;
  434. procedure TTopicCollection.FreeItem(Item: Pointer);
  435. begin
  436. if Item<>nil then DisposeTopic(Item);
  437. end;
  438. function TTopicCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  439. var K1: PTopic absolute Key1;
  440. K2: PTopic absolute Key2;
  441. R: Sw_integer;
  442. begin
  443. if K1^.HelpCtx<K2^.HelpCtx then R:=-1 else
  444. if K1^.HelpCtx>K2^.HelpCtx then R:= 1 else
  445. R:=0;
  446. Compare:=R;
  447. end;
  448. function TTopicCollection.SearchTopic(AHelpCtx: THelpCtx): PTopic;
  449. var T: TTopic;
  450. P: PTopic;
  451. Index: sw_integer;
  452. begin
  453. T.HelpCtx:=AHelpCtx;
  454. if Search(@T,Index) then
  455. P:=At(Index)
  456. else
  457. P:=nil;
  458. SearchTopic:=P;
  459. end;
  460. function TIndexEntryCollection.At(Index: Sw_Integer): PIndexEntry;
  461. begin
  462. At:=inherited At(Index);
  463. end;
  464. procedure TIndexEntryCollection.FreeItem(Item: Pointer);
  465. begin
  466. if Item<>nil then DisposeIndexEntry(Item);
  467. end;
  468. function TUnsortedIndexEntryCollection.At(Index: Sw_Integer): PIndexEntry;
  469. begin
  470. At:=inherited At(Index);
  471. end;
  472. procedure TUnsortedIndexEntryCollection.FreeItem(Item: Pointer);
  473. begin
  474. if Item<>nil then DisposeIndexEntry(Item);
  475. end;
  476. function TIndexEntryCollection.Compare(Key1, Key2: Pointer): Sw_Integer;
  477. var K1: PIndexEntry absolute Key1;
  478. K2: PIndexEntry absolute Key2;
  479. R: Sw_integer;
  480. S1,S2: string;
  481. begin
  482. S1:=UpcaseStr(K1^.Tag^); S2:=UpcaseStr(K2^.Tag^);
  483. if S1<S2 then R:=-1 else
  484. if S1>S2 then R:=1 else
  485. if K1^.FileID<K2^.FileID then R:=-1 else
  486. if K1^.FileID>K2^.FileID then R:= 1 else
  487. R:=0;
  488. Compare:=R;
  489. end;
  490. constructor THelpFile.Init(AID: word);
  491. begin
  492. inherited Init;
  493. ID:=AID;
  494. New(Topics, Init(2000,1000));
  495. New(IndexEntries, Init(2000,1000));
  496. end;
  497. procedure THelpFile.AddTopic(HelpCtx: THelpCtx; Pos: longint; const Param: string);
  498. begin
  499. Topics^.Insert(NewTopic(ID,HelpCtx,Pos,Param));
  500. end;
  501. procedure THelpFile.AddIndexEntry(const Text: string; AHelpCtx: THelpCtx);
  502. begin
  503. IndexEntries^.Insert(NewIndexEntry(Text,ID,AHelpCtx));
  504. end;
  505. function THelpFile.LoadTopic(HelpCtx: THelpCtx): PTopic;
  506. var T: PTopic;
  507. begin
  508. T:=SearchTopic(HelpCtx);
  509. if (T<>nil) then
  510. if T^.Text=nil then
  511. begin
  512. MaintainTopicCache;
  513. if ReadTopic(T)=false then
  514. T:=nil;
  515. if (T<>nil) and (T^.Text=nil) then T:=nil;
  516. end;
  517. if T<>nil then
  518. begin T^.LastAccess:=GetDosTicks; T:=CloneTopic(T); end;
  519. LoadTopic:=T;
  520. end;
  521. function THelpFile.LoadIndex: boolean;
  522. begin
  523. Abstract;
  524. LoadIndex:=false; { remove warning }
  525. end;
  526. function THelpFile.SearchTopic(HelpCtx: THelpCtx): PTopic;
  527. var T: PTopic;
  528. begin
  529. T:=Topics^.SearchTopic(HelpCtx);
  530. SearchTopic:=T;
  531. end;
  532. function THelpFile.ReadTopic(T: PTopic): boolean;
  533. begin
  534. Abstract;
  535. ReadTopic:=false; { remove warning }
  536. end;
  537. procedure THelpFile.MaintainTopicCache;
  538. var Count: sw_integer;
  539. MinLRU: longint;
  540. procedure CountThem(P: PTopic); {$ifndef FPC}far;{$endif}
  541. begin if (P^.Text<>nil) or (P^.Links<>nil) then Inc(Count); end;
  542. procedure SearchLRU(P: PTopic); {$ifndef FPC}far;{$endif}
  543. begin if P^.LastAccess<MinLRU then begin MinLRU:=P^.LastAccess; end; end;
  544. var P: PTopic;
  545. begin
  546. Count:=0; Topics^.ForEach(@CountThem);
  547. if (Count>=TopicCacheSize) then
  548. begin
  549. MinLRU:=MaxLongint; P:=nil; Topics^.ForEach(@SearchLRU);
  550. if P<>nil then
  551. begin
  552. FreeMem(P^.Text,P^.TextSize); P^.TextSize:=0; P^.Text:=nil;
  553. FreeMem(P^.Links,P^.LinkSize); P^.LinkCount:=0; P^.Links:=nil;
  554. end;
  555. end;
  556. end;
  557. destructor THelpFile.Done;
  558. begin
  559. if Topics<>nil then Dispose(Topics, Done);
  560. if IndexEntries<>nil then Dispose(IndexEntries, Done);
  561. inherited Done;
  562. end;
  563. constructor TOAHelpFile.Init(AFileName: string; AID: word);
  564. var OK: boolean;
  565. FS,L: longint;
  566. R: TRecord;
  567. begin
  568. if inherited Init(AID)=false then Fail;
  569. F:=New(PFastBufStream, Init(AFileName, stOpenRead, HelpStreamBufSize));
  570. OK:=F<>nil;
  571. if OK then OK:=(F^.Status=stOK);
  572. if OK then
  573. begin
  574. FS:=F^.GetSize;
  575. OK:=ReadHeader;
  576. end;
  577. while OK do
  578. begin
  579. L:=F^.GetPos;
  580. if (L>=FS) then Break;
  581. OK:=ReadRecord(R,false);
  582. if (OK=false) or (R.SClass=0) or (R.Size=0) then Break;
  583. case R.SClass of
  584. oa_rtContext : begin F^.Seek(L); OK:=ReadTopics; end;
  585. oa_rtText : {Skip};
  586. oa_rtKeyword : {Skip};
  587. oa_rtIndex : begin IndexTablePos:=L; {OK:=ReadIndexTable; }end;
  588. oa_rtCompression : begin F^.Seek(L); OK:=ReadCompression; end;
  589. oa_rtIndexTags : begin IndexTagsPos:=L; {OK:=ReadIndexTags; }end;
  590. else
  591. begin
  592. {$ifdef DEBUGMSG}
  593. ClearFormatParams;
  594. AddFormatParamInt(R.SClass);
  595. AddFormatParamInt(L);
  596. AddFormatParamInt(R.Size);
  597. ErrorBox('Uknown help record tag %x encountered, '+
  598. 'offset %x, size %d',@FormatParams);
  599. {$else}
  600. {Skip};
  601. {$endif}
  602. end;
  603. end;
  604. if OK then
  605. begin Inc(L, SizeOf(THLPRecordHeader)); Inc(L, R.Size); F^.Seek(L); OK:=(F^.Status=stOK); end
  606. end;
  607. OK:=OK and (TopicsRead=true);
  608. if OK=false then Fail;
  609. end;
  610. function TOAHelpFile.LoadIndex: boolean;
  611. begin
  612. LoadIndex:=ReadIndexTable;
  613. end;
  614. function TOAHelpFile.ReadHeader: boolean;
  615. var S: string;
  616. P: longint;
  617. R: TRecord;
  618. OK: boolean;
  619. begin
  620. F^.Seek(0);
  621. F^.Read(S[1],128); S[0]:=#255;
  622. OK:=(F^.Status=stOK); P:=Pos(Signature,S);
  623. OK:=OK and (P>0);
  624. if OK then
  625. begin
  626. F^.Seek(P+length(Signature)-1);
  627. F^.Read(Version,SizeOf(Version));
  628. OK:=(F^.Status=stOK) and (Version.FormatVersion>=MinFormatVersion);
  629. if OK then
  630. begin
  631. OK:=ReadRecord(R,true);
  632. OK:=OK and (R.SClass=oa_rtFileHeader) and (R.Size=SizeOf(Header));
  633. if OK then Move(R.Data^,Header,SizeOf(Header));
  634. DisposeRecord(R);
  635. end;
  636. end;
  637. ReadHeader:=OK;
  638. end;
  639. function TOAHelpFile.ReadTopics: boolean;
  640. var OK: boolean;
  641. R: TRecord;
  642. L,I: longint;
  643. function GetCtxPos(C: THLPContextPos): longint;
  644. begin
  645. GetCtxPos:=longint(C.HiB) shl 16 + C.LoW;
  646. end;
  647. begin
  648. OK:=ReadRecord(R, true);
  649. if OK then
  650. with THLPContexts(R.Data^) do
  651. for I:=1 to longint(ContextCount)-1 do
  652. begin
  653. if Topics^.Count=MaxCollectionSize then Break;
  654. L:=GetCtxPos(Contexts[I]);
  655. if (L and $800000)<>0 then L:=not L;
  656. if (L=-1) and (Header.MainIndexScreen>0) then
  657. L:=GetCtxPos(Contexts[Header.MainIndexScreen]);
  658. if (L>0) then
  659. AddTopic(I,L,'');
  660. end;
  661. DisposeRecord(R);
  662. TopicsRead:=OK;
  663. ReadTopics:=OK;
  664. end;
  665. function TOAHelpFile.ReadIndexTable: boolean;
  666. var OK: boolean;
  667. R: TRecord;
  668. I: longint;
  669. LastTag,S: string;
  670. CurPtr: sw_word;
  671. HelpCtx: THelpCtx;
  672. LenCode,CopyCnt,AddLen: byte;
  673. type pword = ^word;
  674. begin
  675. if IndexTableRead then OK:=true else
  676. begin
  677. LastTag:=''; CurPtr:=0;
  678. OK:=(IndexTablePos<>0);
  679. if OK then begin F^.Seek(IndexTablePos); OK:=F^.Status=stOK; end;
  680. if OK then OK:=ReadRecord(R, true);
  681. if OK then
  682. with THLPIndexTable(R.Data^) do
  683. for I:=0 to IndexCount-1 do
  684. begin
  685. LenCode:=PByteArray(@Entries)^[CurPtr];
  686. AddLen:=LenCode and $1f; CopyCnt:=LenCode shr 5;
  687. S[0]:=chr(AddLen); Move(PByteArray(@Entries)^[CurPtr+1],S[1],AddLen);
  688. LastTag:=copy(LastTag,1,CopyCnt)+S;
  689. HelpCtx:=PWord(@PByteArray(@Entries)^[CurPtr+1+AddLen])^;
  690. AddIndexEntry(LastTag,HelpCtx);
  691. Inc(CurPtr,1+AddLen+2);
  692. end;
  693. DisposeRecord(R);
  694. IndexTableRead:=OK;
  695. end;
  696. ReadIndexTable:=OK;
  697. end;
  698. function TOAHelpFile.ReadCompression: boolean;
  699. var OK: boolean;
  700. R: TRecord;
  701. begin
  702. OK:=ReadRecord(R, true);
  703. OK:=OK and (R.Size=SizeOf(THLPCompression));
  704. if OK then Move(R.Data^,Compression,SizeOf(Compression));
  705. DisposeRecord(R);
  706. CompressionRead:=OK;
  707. ReadCompression:=OK;
  708. end;
  709. function TOAHelpFile.ReadIndexTags: boolean;
  710. var OK: boolean;
  711. begin
  712. OK:={ReadRecord(R, true)}true;
  713. IndexTagsRead:=OK;
  714. ReadIndexTags:=OK;
  715. end;
  716. function TOAHelpFile.ReadRecord(var R: TRecord; ReadData: boolean): boolean;
  717. var OK: boolean;
  718. H: THLPRecordHeader;
  719. begin
  720. FillChar(R, SizeOf(R), 0);
  721. F^.Read(H,SizeOf(H));
  722. OK:=F^.Status=stOK;
  723. if OK then
  724. begin
  725. R.SClass:=H.RecType; R.Size:=H.RecLength;
  726. if (R.Size>0) and ReadData then
  727. begin
  728. GetMem(R.Data,R.Size);
  729. F^.Read(R.Data^,R.Size);
  730. OK:=F^.Status=stOK;
  731. end;
  732. if OK=false then DisposeRecord(R);
  733. end;
  734. ReadRecord:=OK;
  735. end;
  736. function TOAHelpFile.ReadTopic(T: PTopic): boolean;
  737. var SrcPtr,DestPtr,TopicSize: sw_word;
  738. NewR: TRecord;
  739. LinkPosCount: integer;
  740. LinkPos: array[1..50] of TRect;
  741. function IsLinkPosStart(X,Y: integer): boolean;
  742. var OK: boolean;
  743. I: integer;
  744. begin
  745. OK:=false;
  746. for I:=1 to LinkPosCount do
  747. with LinkPos[I] do
  748. if (A.X=X) and (A.Y=Y) then
  749. begin
  750. OK:=true;
  751. Break;
  752. end;
  753. IsLinkPosStart:=OK;
  754. end;
  755. function IsLinkPosEnd(X,Y: integer): boolean;
  756. var OK: boolean;
  757. I: integer;
  758. begin
  759. OK:=false;
  760. for I:=1 to LinkPosCount do
  761. with LinkPos[I] do
  762. if (B.X=X) and (B.Y=Y) then
  763. begin
  764. OK:=true;
  765. Break;
  766. end;
  767. IsLinkPosEnd:=OK;
  768. end;
  769. function ExtractTextRec(var R: TRecord): boolean;
  770. function GetNextNibble: byte;
  771. var B,N: byte;
  772. begin
  773. B:=PByteArray(R.Data)^[SrcPtr div 2];
  774. N:=( B and ($0f shl (4*(SrcPtr mod 2))) ) shr (4*(SrcPtr mod 2));
  775. Inc(SrcPtr);
  776. GetNextNibble:=N;
  777. end;
  778. procedure RealAddChar(C: char);
  779. begin
  780. if Assigned(NewR.Data) then
  781. PByteArray(NewR.Data)^[DestPtr]:=ord(C);
  782. Inc(DestPtr);
  783. end;
  784. var CurX,CurY: integer;
  785. InLink: boolean;
  786. procedure AddChar(C: char);
  787. begin
  788. if IsLinkPosStart(CurX+2,CurY) then
  789. begin
  790. RealAddChar(hscLink);
  791. InLink:=true;
  792. end
  793. else
  794. if (C=hscLineBreak) and (InLink) then
  795. begin
  796. RealAddChar(hscLink);
  797. InLink:=false;
  798. end;
  799. RealAddChar(C);
  800. if IsLinkPosEnd(CurX+2,CurY) then
  801. begin
  802. RealAddChar(hscLink);
  803. InLink:=false;
  804. end;
  805. if C<>hscLineBreak then
  806. Inc(CurX)
  807. else
  808. begin
  809. CurX:=0;
  810. Inc(CurY);
  811. end;
  812. end;
  813. var OK: boolean;
  814. C: char;
  815. P: pointer;
  816. function GetNextChar: char;
  817. var C: char;
  818. I,N,Cnt: byte;
  819. begin
  820. N:=GetNextNibble;
  821. case N of
  822. $00 : C:=#0;
  823. $01..$0D : C:=chr(Compression.CharTable[N]);
  824. ncRawChar : begin
  825. I:=GetNextNibble;
  826. C:=chr(I+GetNextNibble shl 4);
  827. end;
  828. ncRepChar : begin
  829. Cnt:=2+GetNextNibble;
  830. C:=GetNextChar{$ifdef FPC}(){$endif};
  831. for I:=1 to Cnt-1 do AddChar(C);
  832. end;
  833. end;
  834. GetNextChar:=C;
  835. end;
  836. begin
  837. OK:=Compression.CompType in[ctNone,ctNibble];
  838. if OK then
  839. case Compression.CompType of
  840. ctNone : ;
  841. ctNibble :
  842. begin
  843. CurX:=0; CurY:=0; InLink:=false;
  844. NewR.SClass:=0;
  845. NewR.Size:=0;
  846. NewR.Data:=nil;
  847. SrcPtr:=0; DestPtr:=0;
  848. while SrcPtr<(R.Size*2) do
  849. begin
  850. C:=GetNextChar;
  851. AddChar(C);
  852. end;
  853. if InLink then AddChar(hscLineBreak);
  854. TopicSize:=DestPtr;
  855. CurX:=0; CurY:=0; InLink:=false;
  856. NewR.SClass:=R.SClass;
  857. NewR.Size:=Min(MaxHelpTopicSize,TopicSize);
  858. GetMem(NewR.Data, NewR.Size);
  859. SrcPtr:=0; DestPtr:=0;
  860. while SrcPtr<(R.Size*2) do
  861. begin
  862. C:=GetNextChar;
  863. AddChar(C);
  864. end;
  865. if InLink then AddChar(hscLineBreak);
  866. DisposeRecord(R); R:=NewR;
  867. if (R.Size>DestPtr) then
  868. begin
  869. P:=R.Data; GetMem(R.Data,DestPtr);
  870. Move(P^,R.Data^,DestPtr); FreeMem(P,R.Size); R.Size:=DestPtr;
  871. end;
  872. end;
  873. else OK:=false;
  874. end;
  875. ExtractTextRec:=OK;
  876. end;
  877. var OK: boolean;
  878. TextR,KeyWR: TRecord;
  879. I: sw_word;
  880. begin
  881. OK:=T<>nil;
  882. if OK and (T^.Text=nil) then
  883. begin
  884. LinkPosCount:=0; FillChar(LinkPos,Sizeof(LinkPos),0);
  885. FillChar(TextR,SizeOf(TextR),0); FillChar(KeyWR,SizeOf(KeyWR),0);
  886. F^.Seek(T^.FileOfs); OK:=F^.Status=stOK;
  887. if OK then OK:=ReadRecord(TextR,true);
  888. OK:=OK and (TextR.SClass=oa_rtText);
  889. if OK then OK:=ReadRecord(KeyWR,true);
  890. OK:=OK and (KeyWR.SClass=oa_rtKeyword);
  891. if OK then
  892. begin
  893. case Version.FormatVersion of
  894. TP55FormatVersion :
  895. with THLPKeywordRecord55(KeyWR.Data^) do
  896. begin
  897. T^.LinkCount:=KeywordCount;
  898. GetMem(T^.Links,T^.LinkSize);
  899. if T^.LinkCount>0 then
  900. for I:=0 to T^.LinkCount-1 do
  901. with Keywords[I] do
  902. begin
  903. T^.Links^[I].Context:=KwContext;
  904. T^.Links^[I].FileID:=ID;
  905. Inc(LinkPosCount);
  906. with LinkPos[LinkPosCount] do
  907. begin
  908. A.Y:=PosY-1; B.Y:=PosY-1;
  909. A.X:=StartX-1; B.X:=EndX-1;
  910. end;
  911. end;
  912. end;
  913. else
  914. with THLPKeywordRecord(KeyWR.Data^) do
  915. begin
  916. T^.LinkCount:=KeywordCount;
  917. GetMem(T^.Links,T^.LinkSize);
  918. if KeywordCount>0 then
  919. for I:=0 to KeywordCount-1 do
  920. begin
  921. T^.Links^[I].Context:=Keywords[I].KwContext;
  922. T^.Links^[I].FileID:=ID;
  923. end;
  924. end;
  925. end;
  926. end;
  927. if OK then OK:=ExtractTextRec(TextR);
  928. if OK then
  929. if TextR.Size>0 then
  930. begin
  931. T^.Text:=TextR.Data; T^.TextSize:=TextR.Size;
  932. TextR.Data:=nil; TextR.Size:=0;
  933. end;
  934. DisposeRecord(TextR); DisposeRecord(KeyWR);
  935. end;
  936. ReadTopic:=OK;
  937. end;
  938. destructor TOAHelpFile.Done;
  939. begin
  940. if F<>nil then Dispose(F, Done);
  941. inherited Done;
  942. end;
  943. constructor THelpFacility.Init;
  944. begin
  945. inherited Init;
  946. New(HelpFiles, Init(10,10));
  947. IndexTabSize:=40;
  948. end;
  949. function THelpFacility.AddOAHelpFile(const FileName: string): boolean;
  950. var H: PHelpFile;
  951. begin
  952. H:=New(POAHelpFile, Init(FileName, LastID+1));
  953. AddOAHelpFile:=AddFile(H);
  954. end;
  955. function THelpFacility.AddHTMLHelpFile(const FileName, TOCEntry: string): boolean;
  956. var H: PHelpFile;
  957. begin
  958. H:=New(PHTMLHelpFile, Init(FileName, LastID+1, TOCEntry));
  959. AddHTMLHelpFile:=AddFile(H);;
  960. end;
  961. function THelpFacility.AddNGHelpFile(const FileName: string): boolean;
  962. var H: PHelpFile;
  963. begin
  964. H:=New(PNGHelpFile, Init(FileName, LastID+1));
  965. AddNGHelpFile:=AddFile(H);;
  966. end;
  967. function THelpFacility.AddWinHelpFile(const FileName: string): boolean;
  968. var H: PHelpFile;
  969. begin
  970. H:=New(PWinHelpFile, Init(FileName, LastID+1));
  971. AddWinHelpFile:=AddFile(H);;
  972. end;
  973. function THelpFacility.AddHTMLIndexHelpFile(const FileName: string): boolean;
  974. var H: PHelpFile;
  975. begin
  976. H:=New(PHTMLIndexHelpFile, Init(FileName, LastID+1));
  977. AddHTMLIndexHelpFile:=AddFile(H);;
  978. end;
  979. function THelpFacility.AddFile(H: PHelpFile): boolean;
  980. begin
  981. if H<>nil then
  982. begin
  983. HelpFiles^.Insert(H);
  984. Inc(LastID);
  985. end;
  986. AddFile:=H<>nil;
  987. end;
  988. function THelpFacility.SearchTopicOwner(SourceFileID: word; Context: THelpCtx): PHelpFile;
  989. var P: PTopic;
  990. HelpFile: PHelpFile;
  991. function Search(F: PHelpFile): boolean; {$ifndef FPC}far;{$endif}
  992. begin
  993. P:=SearchTopicInHelpFile(F,Context); if P<>nil then HelpFile:=F;
  994. Search:=P<>nil;
  995. end;
  996. begin
  997. HelpFile:=nil;
  998. if SourceFileID=0 then P:=nil else
  999. begin
  1000. HelpFile:=SearchFile(SourceFileID);
  1001. P:=SearchTopicInHelpFile(HelpFile,Context);
  1002. end;
  1003. if P=nil then HelpFiles^.FirstThat(@Search);
  1004. if P=nil then HelpFile:=nil;
  1005. SearchTopicOwner:=HelpFile;
  1006. end;
  1007. function THelpFacility.LoadTopic(SourceFileID: word; Context: THelpCtx): PTopic;
  1008. var P: PTopic;
  1009. H: PHelpFile;
  1010. begin
  1011. if (SourceFileID=0) and (Context=0) then
  1012. P:=BuildIndexTopic else
  1013. begin
  1014. H:=SearchTopicOwner(SourceFileID,Context);
  1015. if (H=nil) then P:=nil else
  1016. P:=H^.LoadTopic(Context);
  1017. end;
  1018. LoadTopic:=P;
  1019. end;
  1020. function THelpFacility.TopicSearch(Keyword: string; var FileID: word; var Context: THelpCtx): boolean;
  1021. function ScanHelpFile(H: PHelpFile): boolean; {$ifndef FPC}far;{$endif}
  1022. function Search(P: PIndexEntry): boolean; {$ifndef FPC}far;{$endif}
  1023. begin
  1024. Search:=copy(UpcaseStr(P^.Tag^),1,length(Keyword))=Keyword;
  1025. end;
  1026. var P: PIndexEntry;
  1027. begin
  1028. H^.LoadIndex;
  1029. P:=H^.IndexEntries^.FirstThat(@Search);
  1030. if P<>nil then begin FileID:=H^.ID; Context:=P^.HelpCtx; end;
  1031. ScanHelpFile:=P<>nil;
  1032. end;
  1033. begin
  1034. Keyword:=UpcaseStr(Keyword);
  1035. TopicSearch:=HelpFiles^.FirstThat(@ScanHelpFile)<>nil;
  1036. end;
  1037. function THelpFacility.BuildIndexTopic: PTopic;
  1038. var T: PTopic;
  1039. Keywords: PIndexEntryCollection;
  1040. Lines: PUnsortedStringCollection;
  1041. procedure InsertKeywordsOfFile(H: PHelpFile); {$ifndef FPC}far;{$endif}
  1042. function InsertKeywords(P: PIndexEntry): boolean; {$ifndef FPC}far;{$endif}
  1043. begin
  1044. Keywords^.Insert(P);
  1045. InsertKeywords:=Keywords^.Count>=MaxCollectionSize;
  1046. end;
  1047. begin
  1048. H^.LoadIndex;
  1049. if Keywords^.Count<MaxCollectionSize then
  1050. H^.IndexEntries^.FirstThat(@InsertKeywords);
  1051. end;
  1052. procedure AddLine(S: string);
  1053. begin
  1054. if S='' then S:=' ';
  1055. Lines^.Insert(NewStr(S));
  1056. end;
  1057. var Line: string;
  1058. procedure FlushLine;
  1059. begin
  1060. if Line<>'' then AddLine(Line); Line:='';
  1061. end;
  1062. var KWCount,NLFlag: sw_integer;
  1063. LastFirstChar: char;
  1064. procedure NewSection(FirstChar: char);
  1065. begin
  1066. if FirstChar<=#64 then FirstChar:=#32;
  1067. FlushLine;
  1068. AddLine('');
  1069. AddLine(FirstChar);
  1070. AddLine('');
  1071. LastFirstChar:=FirstChar;
  1072. NLFlag:=0;
  1073. end;
  1074. function FormatAlias(Alias: string): string;
  1075. var StartP,EndP: sw_integer;
  1076. begin
  1077. repeat
  1078. StartP:=Pos(' ',Alias);
  1079. if StartP>0 then
  1080. begin
  1081. EndP:=StartP;
  1082. while (EndP+1<=length(Alias)) and (Alias[EndP+1]=' ') do Inc(EndP);
  1083. Alias:=copy(Alias,1,StartP-1)+' | '+copy(Alias,EndP+1,High(Alias));
  1084. end;
  1085. until StartP=0;
  1086. if Assigned(HelpFacility) then
  1087. if length(Alias)>IndexTabSize-4 then
  1088. Alias:=Trim(copy(Alias,1,IndexTabSize-4-2))+'..';
  1089. FormatAlias:=Alias;
  1090. end;
  1091. procedure AddKeyword(KWS: string);
  1092. begin
  1093. Inc(KWCount); if KWCount=1 then NLFlag:=0;
  1094. if (KWCount=1) or
  1095. ( (Upcase(KWS[1])<>LastFirstChar) and ( (LastFirstChar>#64) or (KWS[1]>#64) ) ) then
  1096. NewSection(Upcase(KWS[1]));
  1097. KWS:=FormatAlias(KWS);
  1098. if (NLFlag mod 2)=0
  1099. then Line:=' '+#2+KWS+#2
  1100. else begin
  1101. Line:=RExpand(Line,IndexTabSize)+#2+KWS+#2;
  1102. FlushLine;
  1103. end;
  1104. Inc(NLFlag);
  1105. end;
  1106. var KW: PIndexEntry;
  1107. I: sw_integer;
  1108. begin
  1109. New(Keywords, Init(5000,5000));
  1110. HelpFiles^.ForEach(@InsertKeywordsOfFile);
  1111. New(Lines, Init((Keywords^.Count div 2)+100,1000));
  1112. T:=NewTopic(0,0,0,'');
  1113. if HelpFiles^.Count=0 then
  1114. begin
  1115. AddLine('');
  1116. AddLine(' '+msg_nohelpfilesinstalled)
  1117. end else
  1118. begin
  1119. AddLine(' '+msg_helpindex);
  1120. KWCount:=0; Line:='';
  1121. T^.LinkCount:=Min(Keywords^.Count,MaxBytes div sizeof(T^.Links^[0])-1);
  1122. GetMem(T^.Links,T^.LinkSize);
  1123. for I:=0 to T^.LinkCount-1 do
  1124. begin
  1125. KW:=Keywords^.At(I);
  1126. AddKeyword(KW^.Tag^);
  1127. T^.Links^[I].Context:=longint(KW^.HelpCtx);
  1128. T^.Links^[I].FileID:=KW^.FileID;
  1129. end;
  1130. FlushLine;
  1131. AddLine('');
  1132. end;
  1133. RenderTopic(Lines,T);
  1134. Dispose(Lines, Done);
  1135. Keywords^.DeleteAll; Dispose(Keywords, Done);
  1136. BuildIndexTopic:=T;
  1137. end;
  1138. function THelpFacility.SearchFile(ID: byte): PHelpFile;
  1139. function Match(P: PHelpFile): boolean; {$ifndef FPC}far;{$endif}
  1140. begin
  1141. Match:=(P^.ID=ID);
  1142. end;
  1143. begin
  1144. SearchFile:=HelpFiles^.FirstThat(@Match);
  1145. end;
  1146. function THelpFacility.SearchTopicInHelpFile(F: PHelpFile; Context: THelpCtx): PTopic;
  1147. var P: PTopic;
  1148. begin
  1149. if F=nil then P:=nil else
  1150. P:=F^.SearchTopic(Context);
  1151. SearchTopicInHelpFile:=P;
  1152. end;
  1153. destructor THelpFacility.Done;
  1154. begin
  1155. inherited Done;
  1156. Dispose(HelpFiles, Done);
  1157. end;
  1158. END.
  1159. {
  1160. $Log$
  1161. Revision 1.1 2000-07-13 09:48:37 michael
  1162. + Initial import
  1163. Revision 1.26 2000/07/03 08:54:54 pierre
  1164. * Some enhancements for WinHelp support by G abor
  1165. Revision 1.25 2000/06/26 07:29:23 pierre
  1166. * new bunch of Gabor's changes
  1167. Revision 1.24 2000/06/22 09:07:14 pierre
  1168. * Gabor changes: see fixes.txt
  1169. Revision 1.23 2000/06/16 08:50:44 pierre
  1170. + new bunch of Gabor's changes
  1171. Revision 1.22 2000/05/31 20:42:02 pierre
  1172. * fixthe TRect problem by 'using' windows before objects
  1173. Revision 1.21 2000/05/30 07:18:33 pierre
  1174. + colors for HTML help by Gabor
  1175. Revision 1.20 2000/05/29 10:44:59 pierre
  1176. + New bunch of Gabor's changes: see fixes.txt
  1177. Revision 1.19 2000/04/25 08:42:35 pierre
  1178. * New Gabor changes : see fixes.txt
  1179. Revision 1.18 2000/04/18 11:42:38 pierre
  1180. lot of Gabor changes : see fixes.txt
  1181. Revision 1.17 2000/02/07 11:47:25 pierre
  1182. * Remove 64Kb limitation for FPC by Gabor
  1183. Revision 1.16 2000/01/03 14:59:03 marco
  1184. * Fixed Linux code that got time of day. Removed Timezone parameter
  1185. Revision 1.15 1999/08/16 18:25:29 peter
  1186. * Adjusting the selection when the editor didn't contain any line.
  1187. * Reserved word recognition redesigned, but this didn't affect the overall
  1188. syntax highlight speed remarkably (at least not on my Amd-K6/350).
  1189. The syntax scanner loop is a bit slow but the main problem is the
  1190. recognition of special symbols. Switching off symbol processing boosts
  1191. the performance up to ca. 200%...
  1192. * The editor didn't allow copying (for ex to clipboard) of a single character
  1193. * 'File|Save as' caused permanently run-time error 3. Not any more now...
  1194. * Compiler Messages window (actually the whole desktop) did not act on any
  1195. keypress when compilation failed and thus the window remained visible
  1196. + Message windows are now closed upon pressing Esc
  1197. + At 'Run' the IDE checks whether any sources are modified, and recompiles
  1198. only when neccessary
  1199. + BlockRead and BlockWrite (Ctrl+K+R/W) implemented in TCodeEditor
  1200. + LineSelect (Ctrl+K+L) implemented
  1201. * The IDE had problems closing help windows before saving the desktop
  1202. Revision 1.14 1999/07/18 16:26:42 florian
  1203. * IDE compiles with for Win32 and basic things are working
  1204. Revision 1.13 1999/04/13 10:47:51 daniel
  1205. * Fixed for Linux
  1206. Revision 1.12 1999/04/07 21:56:00 peter
  1207. + object support for browser
  1208. * html help fixes
  1209. * more desktop saving things
  1210. * NODEBUG directive to exclude debugger
  1211. Revision 1.11 1999/03/16 12:38:16 peter
  1212. * tools macro fixes
  1213. + tph writer
  1214. + first things for resource files
  1215. Revision 1.10 1999/03/08 14:58:19 peter
  1216. + prompt with dialogs for tools
  1217. Revision 1.9 1999/03/03 16:44:05 pierre
  1218. * TPH reader fix from Peter
  1219. Revision 1.8 1999/03/01 15:42:11 peter
  1220. + Added dummy entries for functions not yet implemented
  1221. * MenuBar didn't update itself automatically on command-set changes
  1222. * Fixed Debugging/Profiling options dialog
  1223. * TCodeEditor converts spaces to tabs at save only if efUseTabChars is
  1224. set
  1225. * efBackSpaceUnindents works correctly
  1226. + 'Messages' window implemented
  1227. + Added '$CAP MSG()' and '$CAP EDIT' to available tool-macros
  1228. + Added TP message-filter support (for ex. you can call GREP thru
  1229. GREP2MSG and view the result in the messages window - just like in TP)
  1230. * A 'var' was missing from the param-list of THelpFacility.TopicSearch,
  1231. so topic search didn't work...
  1232. * In FPHELP.PAS there were still context-variables defined as word instead
  1233. of THelpCtx
  1234. * StdStatusKeys() was missing from the statusdef for help windows
  1235. + Topic-title for index-table can be specified when adding a HTML-files
  1236. Revision 1.6 1999/02/20 15:18:35 peter
  1237. + ctrl-c capture with confirm dialog
  1238. + ascii table in the tools menu
  1239. + heapviewer
  1240. * empty file fixed
  1241. * fixed callback routines in fpdebug to have far for tp7
  1242. Revision 1.5 1999/02/19 15:43:22 peter
  1243. * compatibility fixes for FV
  1244. Revision 1.4 1999/02/18 13:44:37 peter
  1245. * search fixed
  1246. + backward search
  1247. * help fixes
  1248. * browser updates
  1249. Revision 1.3 1999/02/08 10:37:46 peter
  1250. + html helpviewer
  1251. Revision 1.2 1998/12/28 15:47:56 peter
  1252. + Added user screen support, display & window
  1253. + Implemented Editor,Mouse Options dialog
  1254. + Added location of .INI and .CFG file
  1255. + Option (INI) file managment implemented (see bottom of Options Menu)
  1256. + Switches updated
  1257. + Run program
  1258. Revision 1.4 1998/12/22 10:39:55 peter
  1259. + options are now written/read
  1260. + find and replace routines
  1261. }