mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-10 05:28:44 +02:00
275 lines
7.1 KiB
ObjectPascal
275 lines
7.1 KiB
ObjectPascal
{
|
|
This file is part of the Free Pascal Integrated Development Environment
|
|
Copyright (c) 1998 by Berczi Gabor
|
|
|
|
Routines to create .tph files
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
unit WTPHWriter;
|
|
|
|
interface
|
|
|
|
uses
|
|
Objects, WoaHelp, WHelp;
|
|
|
|
const
|
|
HelpStamp = 'TURBO PASCAL HelpFile.';
|
|
|
|
DefFormatVersion = $34;
|
|
|
|
type
|
|
PHelpFileWriter = ^THelpFileWriter;
|
|
THelpFileWriter = object(TOAHelpFile)
|
|
constructor Init(AFileName: string; AID: word);
|
|
function CreateTopic(HelpCtx: THelpCtx): PTopic; virtual;
|
|
procedure AddTopicToIndex(IndexTag: string; P: PTopic); virtual;
|
|
procedure AddLineToTopic(P: PTopic; Line: string); virtual;
|
|
procedure AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);
|
|
procedure AddIndexEntry(Tag: string; P: PTopic); virtual;
|
|
function WriteFile: boolean; virtual;
|
|
destructor Done; virtual;
|
|
private
|
|
procedure CompleteContextNo;
|
|
procedure CalcTopicOfs;
|
|
procedure WriteHeader(var S: TStream);
|
|
procedure WriteCompressionRecord(var S: TStream);
|
|
procedure WriteContextTable(var S: TStream);
|
|
procedure WriteIndexTable(var S: TStream);
|
|
procedure WriteTopic(var S: TStream; T: PTopic);
|
|
procedure WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);
|
|
end;
|
|
|
|
implementation
|
|
|
|
constructor THelpFileWriter.Init(AFileName: string; AID: word);
|
|
var OK: boolean;
|
|
begin
|
|
THelpFile.Init(AID);
|
|
New(F, Init(AFileName, stCreate, HelpStreamBufSize));
|
|
OK:=F<>nil;
|
|
if OK then OK:=(F^.Status=stOK);
|
|
if OK=false then Fail;
|
|
end;
|
|
|
|
function THelpFileWriter.CreateTopic(HelpCtx: THelpCtx): PTopic;
|
|
var P: PTopic;
|
|
begin
|
|
if (HelpCtx<>0) and (SearchTopic(HelpCtx)<>nil) then
|
|
P:=nil
|
|
else
|
|
begin
|
|
P:=NewTopic(ID,HelpCtx,0,'');
|
|
Topics^.Insert(P);
|
|
end;
|
|
CreateTopic:=P;
|
|
end;
|
|
|
|
procedure THelpFileWriter.AddTopicToIndex(IndexTag: string; P: PTopic);
|
|
begin
|
|
IndexEntries^.Insert(NewIndexEntry(IndexTag,P^.FileID,P^.HelpCtx));
|
|
end;
|
|
|
|
procedure THelpFileWriter.AddLineToTopic(P: PTopic; Line: string);
|
|
var OldText: pointer;
|
|
OldSize: word;
|
|
begin
|
|
if P=nil then Exit;
|
|
OldText:=P^.Text; OldSize:=P^.TextSize;
|
|
Inc(P^.TextSize,length(Line)+1);
|
|
GetMem(P^.Text,P^.TextSize);
|
|
if OldText<>nil then Move(OldText^,P^.Text^,OldSize);
|
|
Move(Line[1],P^.Text^[OldSize],length(Line));
|
|
P^.Text^[OldSize+length(Line)]:=0;
|
|
if OldText<>nil then FreeMem(OldText,OldSize);
|
|
end;
|
|
|
|
procedure THelpFileWriter.AddLinkToTopic(P: PTopic; AHelpCtx: THelpCtx);
|
|
var OldEntries: pointer;
|
|
OldCount : word;
|
|
OldSize : word;
|
|
begin
|
|
if P=nil then Exit;
|
|
OldEntries:=P^.Links; OldCount:=P^.LinkCount; OldSize:=P^.LinkSize;
|
|
Inc(P^.LinkCount);
|
|
GetMem(P^.Links,P^.LinkSize);
|
|
if OldEntries<>nil then Move(OldEntries^,P^.Links^,OldSize);
|
|
with P^.Links^[P^.LinkCount-1] do
|
|
begin
|
|
FileID:=ID;
|
|
Context:=AHelpCtx;
|
|
end;
|
|
if OldEntries<>nil then FreeMem(OldEntries,OldSize);
|
|
end;
|
|
|
|
procedure THelpFileWriter.AddIndexEntry(Tag: string; P: PTopic);
|
|
begin
|
|
if P=nil then Exit;
|
|
IndexEntries^.Insert(NewIndexEntry(Tag,P^.FileID,P^.HelpCtx));
|
|
end;
|
|
|
|
function THelpFileWriter.WriteFile: boolean;
|
|
var I: sw_integer;
|
|
CtxStart: longint;
|
|
begin
|
|
CompleteContextNo;
|
|
CalcTopicOfs;
|
|
|
|
WriteHeader(F^);
|
|
WriteCompressionRecord(F^);
|
|
CtxStart:=F^.GetPos;
|
|
WriteContextTable(F^);
|
|
WriteIndexTable(F^);
|
|
for I:=0 to Topics^.Count-1 do
|
|
begin
|
|
WriteTopic(F^,Topics^.At(I));
|
|
end;
|
|
F^.Seek(CtxStart);
|
|
WriteContextTable(F^);
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteHeader(var S: TStream);
|
|
var St: string;
|
|
begin
|
|
Version.FormatVersion:=DefFormatVersion;
|
|
|
|
St:=HelpStamp+#0#$1a;
|
|
F^.Write(St[1],length(St));
|
|
St:=Signature;
|
|
F^.Write(St[1],length(St));
|
|
F^.Write(Version,SizeOf(Version));
|
|
|
|
WriteRecord(F^,rtFileHeader,Header,SizeOf(Header));
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteCompressionRecord(var S: TStream);
|
|
var CR: THLPCompression;
|
|
begin
|
|
FillChar(CR,SizeOf(CR),0);
|
|
WriteRecord(F^,rtCompression,CR,SizeOf(CR));
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteIndexTable(var S: TStream);
|
|
const BufSize = 65000;
|
|
var P: ^THLPIndexTable;
|
|
TableSize: word;
|
|
procedure AddByte(B: byte);
|
|
begin
|
|
PByteArray(@P^.Entries)^[TableSize]:=B;
|
|
Inc(TableSize);
|
|
end;
|
|
procedure AddEntry(Tag: string; HelpCtx: word);
|
|
var Len,I: byte;
|
|
begin
|
|
Len:=length(Tag); if Len>31 then Len:=31;
|
|
AddByte(Len);
|
|
for I:=1 to Len do
|
|
AddByte(ord(Tag[I]));
|
|
AddByte(Lo(HelpCtx)); AddByte(Hi(HelpCtx));
|
|
end;
|
|
var I: sw_integer;
|
|
begin
|
|
if IndexEntries^.Count=0 then Exit;
|
|
GetMem(P,BufSize);
|
|
|
|
TableSize:=0;
|
|
P^.IndexCount:=IndexEntries^.Count;
|
|
for I:=0 to IndexEntries^.Count-1 do
|
|
with IndexEntries^.At(I)^ do
|
|
AddEntry(Tag^,HelpCtx);
|
|
Inc(TableSize,SizeOf(P^.IndexCount));
|
|
WriteRecord(F^,rtIndex,P^,TableSize);
|
|
|
|
FreeMem(P,BufSize);
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteContextTable(var S: TStream);
|
|
var Ctxs: ^THLPContexts;
|
|
CtxSize,I: word;
|
|
T: PTopic;
|
|
MaxCtx: longint;
|
|
begin
|
|
if Topics^.Count=0 then MaxCtx:=1 else
|
|
MaxCtx:=Topics^.At(Topics^.Count-1)^.HelpCtx;
|
|
CtxSize:=SizeOf(Ctxs^.ContextCount)+SizeOf(Ctxs^.Contexts[0])*(MaxCtx+1);
|
|
GetMem(Ctxs,CtxSize); FillChar(Ctxs^,CtxSize,0);
|
|
Ctxs^.ContextCount:=MaxCtx+1;
|
|
for I:=1 to Topics^.Count do
|
|
begin
|
|
T:=Topics^.At(I-1);
|
|
with Ctxs^.Contexts[T^.HelpCtx] do
|
|
begin
|
|
LoW:=(T^.FileOfs and $ffff);
|
|
HiB:=(T^.FileOfs shr 16) and $ff;
|
|
end;
|
|
end;
|
|
WriteRecord(F^,rtContext,Ctxs^,CtxSize);
|
|
FreeMem(Ctxs,CtxSize);
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteTopic(var S: TStream; T: PTopic);
|
|
var TextBuf: PByteArray;
|
|
TextSize: word;
|
|
KWBuf: ^THLPKeywordRecord;
|
|
I,KWBufSize: word;
|
|
begin
|
|
T^.FileOfs:=S.GetPos;
|
|
TextBuf:=T^.Text; TextSize:=T^.TextSize;
|
|
WriteRecord(F^,rtText,TextBuf^,TextSize);
|
|
{ write keyword record here }
|
|
KWBufSize:=SizeOf(KWBuf^)+SizeOf(KWBuf^.Keywords[0])*T^.LinkCount;
|
|
GetMem(KWBuf,KWBufSize); FillChar(KWBuf^,KWBufSize,0);
|
|
KWBuf^.KeywordCount:=T^.LinkCount;
|
|
for I:=0 to T^.LinkCount-1 do
|
|
KWBuf^.Keywords[I].kwContext:=T^.Links^[I].Context;
|
|
WriteRecord(F^,rtKeyword,KWBuf^,KWBufSize);
|
|
FreeMem(KWBuf,KWBufSize);
|
|
end;
|
|
|
|
procedure THelpFileWriter.CompleteContextNo;
|
|
var P: PTopic;
|
|
NextTopicID: THelpCtx;
|
|
function SearchNextFreeTopicID: THelpCtx;
|
|
begin
|
|
while Topics^.SearchTopic(NextTopicID)<>nil do
|
|
Inc(NextTopicID);
|
|
SearchNextFreeTopicID:=NextTopicID;
|
|
end;
|
|
begin
|
|
NextTopicID:=1;
|
|
repeat
|
|
P:=Topics^.SearchTopic(0);
|
|
if P<>nil then
|
|
begin
|
|
Topics^.Delete(P);
|
|
P^.HelpCtx:=SearchNextFreeTopicID;
|
|
Topics^.Insert(P);
|
|
end;
|
|
until P=nil;
|
|
end;
|
|
|
|
procedure THelpFileWriter.CalcTopicOfs;
|
|
begin
|
|
end;
|
|
|
|
procedure THelpFileWriter.WriteRecord(var S: TStream; RecType: byte; var Buf; Size: word);
|
|
var RH: THLPRecordHeader;
|
|
begin
|
|
RH.RecType:=RecType; RH.RecLength:=Size;
|
|
S.Write(RH,SizeOf(RH));
|
|
S.Write(Buf,Size);
|
|
end;
|
|
|
|
destructor THelpFileWriter.Done;
|
|
begin
|
|
inherited Done;
|
|
end;
|
|
|
|
END.
|