home *** CD-ROM | disk | FTP | other *** search
/ Hot Shareware 32 / hot34.iso / ficheros / DTOOL / INTER57G.ZIP / INT2TPH.ZIP / TPH.PAS < prev    next >
Pascal/Delphi Source File  |  1997-07-06  |  20KB  |  808 lines

  1. { TPH unit for the Interrupt List -> .TPH compiler.            }
  2. { The software included, data formats and basic algorithms are }
  3. { copyright (C) 1996 by Slava Gostrenko. All rights reserved.  }
  4.  
  5. {$X+}
  6. unit
  7.   TPH;
  8.  
  9. interface
  10.  
  11. uses
  12.   Objects;
  13.  
  14. const
  15.   HexChars = ['0'..'9', 'A'..'F', 'a'..'f'];
  16.  
  17.   TPFileStamp = 'TURBO PASCAL HELP FILE.'#0
  18.               + #$1A
  19.               + '$*$* &&&&$*$'#0
  20.               + #$34#02;
  21.   FileStamp : array [0 .. Length (TPFileStamp) - 1] of Char = TPFileStamp;
  22.  
  23.   Of_CaseSense = $0004;
  24.  
  25.   CT_Nibble = 2;
  26.  
  27.   NC_RawChar = $F;
  28.   NC_RepChar = $E;
  29.  
  30. type
  31.   TRecType =
  32.     (RT_FileHeader,
  33.      RT_Context,
  34.      RT_Text,
  35.      RT_Keyword,
  36.      RT_Index,
  37.      RT_Compression,
  38.      RT_ScreenTags);
  39.  
  40.   TRecHdr = record
  41.     RecType: TRecType;
  42.     RecLength: Word;
  43.   end;
  44.  
  45.   TPFileHdrRec = record
  46.     Options: Word;
  47.     MainIndexScreen: Word;
  48.     MaxScreenSize: Word;
  49.     Height: Byte;
  50.     Width: Byte;
  51.     LeftMargin: Byte;
  52.   end;
  53.  
  54.   TPCompRec = record
  55.     CompType: Byte;
  56.     CharTable: array [0..13] of Char;
  57.   end;
  58.  
  59.   TFileStart = record
  60.     FileHdr_ : TRecHdr;
  61.     FileHdr  : TPFileHdrRec;
  62.     CompRec_ : TRecHdr;
  63.     CompRec  : TPCompRec;
  64.   end;
  65.  
  66.   PCtxTbl = ^TCtxTbl;
  67.   TCtxTbl = record
  68.     N: Word;
  69.     T: array [0..16382] of Longint;
  70.   end;
  71.  
  72.   TCharCounter = array [Char] of Longint;
  73.  
  74.   PIdxTbl = ^TIdxTbl;
  75.   TIdxTbl = object (TSortedCollection)
  76.     function  KeyOf (Item: Pointer): Pointer; virtual;
  77.     function  Compare (Key1, Key2: Pointer): Integer; virtual;
  78.     procedure SetCtxs;
  79.     function  RealCount: Word;
  80.     procedure Write (var S: TStream);
  81.     procedure AltWrite (var S: TStream; const GlobalAltName: string);
  82.     procedure ReBuild (Level: Integer);
  83.   end;
  84.  
  85.   PTopic = ^TTopic;
  86.   TTopic = object (TStringCollection)
  87.     Size: Longint;
  88.     Keywords: TStringCollection;
  89.     InSwap: Boolean;
  90.     SwapPos: Longint;
  91.  
  92.     constructor Init(ALimit, ADelta: Integer);
  93.  
  94.     procedure   Store2Swap (var S: TStream);
  95.     procedure   RestoreFromSwap (var S: TStream);
  96.  
  97.     procedure   AddString (S: string);
  98.     procedure   UpdateCharCounter (var C: TCharCounter);
  99.     procedure   Write (var S: TStream; Compression: TPCompRec);
  100.  
  101.     procedure   AddKeyword (S: string; StepBack: Integer);
  102.     procedure   WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
  103.   end;
  104.  
  105.   PIndexEntry = ^TIndexEntry;
  106.   TIndexEntry = object (TObject)
  107.     PS, PS1: PString;
  108.     Ctx: Word;
  109.     Topic: PTopic;
  110.     Indexed: Boolean;
  111.  
  112.     constructor Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
  113.     procedure   Write (var S: TStream; const PrevStr: string);
  114.     procedure   AltWrite (var S: TStream);
  115.     destructor  Done; virtual;
  116.   end;
  117.  
  118.   PHelpFile = ^THelpFile;
  119.   THelpFile = object (TBufStream)
  120.     FileStart: TFileStart;
  121.     CtxTbl: PCtxTbl;
  122.     IdxTbl: TIdxTbl;
  123.  
  124.     constructor Init(FileName: FNameStr; Mode, Size: Word);
  125.     destructor  Done; virtual;
  126.   end;
  127.  
  128. var
  129.   SwapFile: PBufStream;
  130.  
  131. implementation
  132.  
  133. uses
  134.   Upcaser;
  135.  
  136. procedure CharCounter2CompRec (var C: TCharCounter; var R: TPCompRec);
  137. var I: Integer;
  138.     J, MC: Char;
  139.     M: Longint;
  140. begin
  141.   for I := Low (R. CharTable) + 1 to High (R. CharTable) do begin
  142.     M := 0;
  143.     MC := #0;
  144.  
  145.     for J := Low (C) to High (C) do
  146.       if C [J] > M then begin
  147.         MC := J;
  148.         M := C [J];
  149.       end;
  150.  
  151.     R. CharTable [I] := MC;
  152.     C [MC] := 0;
  153.   end;
  154. end;
  155.  
  156. { TTopic = object (TStringCollection) }
  157.  
  158. constructor TTopic. Init(ALimit, ADelta: Integer);
  159. begin
  160.   inherited Init (ALimit, ADelta);
  161.   Size := 0;
  162.   Keywords. Init (ALimit, ADelta);
  163.  
  164.   InSwap := False;
  165.   SwapPos := -1;
  166. end;
  167.  
  168. procedure   TTopic. Store2Swap (var S: TStream);
  169. var I: Integer;
  170. begin
  171.   if not InSwap then begin
  172.     if SwapPos = -1 then begin
  173.       SwapPos := S. GetSize;
  174.       S. Seek (SwapPos);
  175.       S. Write (Count, 2);
  176.       if Count > 1 then
  177.         for I := 1 to Count - 1 do begin
  178.           S. WriteStr (Items^[I]);
  179.           DisposeStr (Items^[I]);
  180.           Items^[I] := nil;
  181.         end;
  182.     end else
  183.       if Count > 1 then
  184.         for I := 1 to Count - 1 do begin
  185.           DisposeStr (Items^[I]);
  186.           Items^[I] := nil;
  187.         end;
  188.  
  189.     InSwap := True;
  190.   end;
  191. end;
  192.  
  193. procedure   TTopic. RestoreFromSwap (var S: TStream);
  194. var I, C: Integer;
  195. begin
  196.   if InSwap then
  197.     if SwapPos = -1 then begin
  198.       WriteLn ('Swapping error 2');
  199.       Halt (1);
  200.     end else begin
  201.       S. Seek (SwapPos);
  202.       S. Read (C, 2);
  203.       if C > 1 then
  204.         for I := 1 to C - 1 do
  205.           Items^[I] := S. ReadStr;
  206.       InSwap := False;
  207.     end;
  208. end;
  209.  
  210. procedure   TTopic. AddString (S: string);
  211. var I, J: Integer;
  212. begin
  213.   AtInsert (Count, NewStr (S));
  214.  
  215.   if Length (S) < 77 then begin
  216.     Inc (Size, Length (S) + 1);
  217.   end else begin
  218.     I := 77;
  219.  
  220.     while (I > Length (S) - 75) and (S [I] <> ' ') do
  221.       Dec (I);
  222.  
  223.     Inc (Size, I);
  224.  
  225.     J := I - 1 - (Length (S) - I + 1);
  226.     if J < 0 then
  227.       J := 0;
  228.  
  229.     Inc (Size, J + Length (S) - I + 1 + 1);
  230.   end;
  231.  
  232.   if Size > 65535 then
  233.     WriteLn ('error 1');
  234. end;
  235.  
  236. procedure TTopic. UpdateCharCounter (var C: TCharCounter);
  237.   procedure DoOneString (PS: PString); far;
  238.   var I: Integer;
  239.   begin
  240.     if PS <> nil then
  241.       for I := 1 to Length (PS^) do
  242.         Inc (C [PS^ [I]]);
  243.   end;
  244. begin
  245.   RestoreFromSwap (SwapFile^);
  246.   ForEach (@DoOneString);
  247.   Store2Swap (SwapFile^);
  248. end;
  249.  
  250. procedure TTopic. Write (var S: TStream; Compression: TPCompRec);
  251. var
  252.   Buf: Byte;
  253.   Nibble: Integer;
  254.  
  255.   procedure  WriteNibble (X: Byte);
  256.   begin
  257.     if Nibble = 0 then begin
  258.       Buf := X;
  259.       Nibble := 1;
  260.     end else begin
  261.       Buf := Buf + X shl 4;
  262.       S. Write (Buf, 1);
  263.       Nibble := 0;
  264.     end;
  265.   end;
  266.  
  267.   procedure  WriteChar (C: Char);
  268.   var I: Integer;
  269.   begin
  270.     I := Pos (C, Compression. CharTable);
  271.     if I > 0 then
  272.       WriteNibble (I - 1)
  273.     else begin
  274.       WriteNibble (NC_RawChar);
  275.       WriteNibble (Ord (C) and $F);
  276.       WriteNibble (Ord (C) shr 4);
  277.     end;
  278.   end;
  279.  
  280.   procedure WriteOneString (PS: PString); far;
  281.     procedure DoWrite (const S: string);
  282.     var I, J: Integer;
  283.     begin
  284.       for I := 1 to Length (S) do begin
  285.         J := I + 1;
  286.         while (J <= Length (S)) and (S [J] = S [I]) do
  287.          Inc (J);
  288.         if ((Pos (S [I], Compression. CharTable) = 0) and (J - I > 1))
  289.         or (J - I > 2) then begin
  290.           WriteNibble (NC_RepChar);
  291.           if J - I > 17 then
  292.             J := I + 17;
  293.           WriteNibble (J - I - 2);
  294.           WriteChar (S [I]);
  295.           I := J - 1;
  296.         end else
  297.           WriteChar (S [I]);
  298.       end;
  299.  
  300.       WriteNibble (0);
  301.     end;
  302.   var I, J, KeyCnt, AllKeysCnt: Integer;
  303.       Spcs: string;
  304.   begin
  305.     if PS <> nil then
  306.       if Length (PS^) < 77 then
  307.         DoWrite (PS^)
  308.       else begin
  309.         AllKeysCnt := 0;
  310.         KeyCnt := 0;
  311.         for I := 1 to Length (PS^) do
  312.           if PS^ [I] = #2 then begin
  313.             Inc (AllKeysCnt);
  314.             if I <= 76 then
  315.               Inc (KeyCnt);
  316.           end;
  317.  
  318.         I := 77;
  319.  
  320.         while Odd (KeyCnt)
  321.         or   ((I > Length (PS^) - 75)
  322.           and (not (PS^ [I] in [' ']))
  323.           and (not (PS^ [I - 1] in [','])))
  324.         do begin
  325.           Dec (I);
  326.           if PS^ [I] = #2 then
  327.             Dec (KeyCnt);
  328.         end;
  329.  
  330.         DoWrite (Copy (PS^, 1, I - 1));
  331.  
  332.         J := I - 1 - (Length (PS^) - I + 1) - KeyCnt + (AllKeysCnt - KeyCnt);
  333.         if J > 0 then begin
  334.           Spcs [0] := Chr (J);
  335.           FillChar (Spcs [1], Ord (Spcs [0]), ' ');
  336.         end else
  337.           Spcs := '';
  338.  
  339.         DoWrite (Spcs + Copy (PS^, I, Length (PS^) - I + 1));
  340.       end
  341.     else
  342.       DoWrite ('');
  343.   end;
  344.  
  345. var
  346.   R: TRecHdr;
  347.   TextRecStart,
  348.   TextRecEnd: Longint;
  349.  
  350. begin
  351.   RestoreFromSwap (SwapFile^);
  352.  
  353.   TextRecStart := S. GetPos;
  354.   R. RecType := RT_Text;
  355.   R. RecLength := 0;
  356.   S. Write (R, SizeOf (R));
  357.  
  358.   Nibble := 0;
  359.   ForEach (@WriteOneString);
  360.  
  361.   WriteChar (#1);
  362.  
  363.   if Nibble = 1 then
  364.     WriteNibble (0);
  365.  
  366.   TextRecEnd := S. GetPos;
  367.   R. RecLength := TextRecEnd - TextRecStart - SizeOf (R);
  368.   S. Seek (TextRecStart);
  369.   S. Write (R, SizeOf (R));
  370.   S. Seek (TextRecEnd);
  371.  
  372.   Store2Swap (SwapFile^);
  373. end;
  374.  
  375. procedure   TTopic. AddKeyword (S: string; StepBack: Integer);
  376. begin
  377.   Keywords. AtInsert (Keywords. Count - StepBack, NewStr (S));
  378. end;
  379.  
  380. procedure   TTopic. WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
  381. var
  382.   R: TRecHdr;
  383.   TmpW: Word;
  384.   I, J, K, MinL, SaveMinLIdx, MatchLen, DecCnt: Integer;
  385.   TmpS, MatchS, Helper: string;
  386.   MatchFound: Boolean;
  387. begin
  388.   R. RecType := RT_Keyword;
  389.   R. RecLength := 6 + Keywords. Count * 2;
  390.   S. Write (R, SizeOf (R));
  391.  
  392.   TmpW := 0;
  393.   S. Write (TmpW, SizeOf (TmpW));
  394.   TmpW := 0;
  395.   S. Write (TmpW, SizeOf (TmpW));
  396.  
  397.   TmpW := Keywords. Count;
  398.   S. Write (TmpW, SizeOf (TmpW));
  399.  
  400.   if Keywords. Count > 0 then
  401.     for I := 0 to Keywords. Count - 1 do begin
  402.       TmpS := StUpcase2 (PString (Keywords. At (I))^);
  403.  
  404.       J := Pos ('"', TmpS);
  405.       if J > 0 then begin
  406.         if TmpS [Length (TmpS)] <> '"' then begin
  407.           Helper := '';
  408.           WriteLn ('error in keyword format - ', TmpS)
  409.         end else begin
  410.           Helper := Copy (TmpS, J + 1, Length (TmpS) - J - 1);
  411.           TmpS [0] := Chr (J - 1);
  412.         end;
  413.       end else
  414.         Helper := '';
  415.  
  416.       DecCnt := 0;
  417.  
  418.       MatchFound := False;
  419.       MinL := High (MinL);
  420.  
  421.       repeat
  422.         IdxTbl. Search (@TmpS, J);
  423.         for K := J to IdxTbl. Count - 1 do begin
  424.           MatchS := StUpcase2 (PIndexEntry (IdxTbl. At (K))^.PS^);
  425.           if Copy (MatchS, 1, Length (TmpS))
  426.           <> TmpS then
  427.             Break
  428.           else begin
  429.             if  ((Helper = '')
  430.               or (Pos (Helper, StUpcase2 (PString (PIndexEntry (
  431.                        IdxTbl. At (K))^. Topic^. At (0))^)) > 0))
  432.             and (Length (MatchS) - Length (TmpS) < MinL)
  433.             then begin
  434.               MinL := Length (MatchS) - Length (TmpS);
  435.               MatchLen := Length (TmpS);
  436.               SaveMinLIdx := K;
  437.             end;
  438.           end;
  439.         end;
  440.  
  441.         if (DecCnt < 2) and (MinL < High (MinL)) then begin
  442.           MatchFound := True;
  443.           J := SaveMinLIdx;
  444.         end;
  445.  
  446.         Dec (TmpS [0]);
  447.         Inc (DecCnt);
  448.       until MatchFound or (Length (TmpS) < 2);
  449.  
  450.       if (Helper <> '') and (MinL < High (MinL)) then
  451.         MinL := 0;
  452.  
  453.       if not MatchFound then begin
  454.         MatchFound := MinL < High (MinL);
  455.         J := SaveMinLIdx;
  456.       end;
  457.  
  458.       if  ( ((Helper = '') or (MinL = High (MinL)))
  459.         and (((MatchLen < 4) and (MinL > 0)) or (MinL > 1))
  460.           )
  461.       and (TmpS [1] in HexChars) and (TmpS [2] in HexChars) then begin
  462.         TmpS := 'INT ' + TmpS [1] + TmpS [2];
  463.         if not IdxTbl. Search (@TmpS, J) then begin
  464.           WriteLn ('error searching for - ', TmpS);
  465.         end else begin
  466.           MinL := 0;
  467.           MatchFound := True;
  468.         end;
  469.       end;
  470.  
  471.       if  ( ((Helper = '') or (MinL = High (MinL)))
  472.         and (((MatchLen < 5) and (MinL > 0)) or (MinL > 1))
  473.           )
  474.       and (TmpS [1] = 'P')
  475.       and (TmpS [2] in HexChars + ['x', 'X']) and (TmpS [3] in HexChars + ['x', 'X'])
  476.       and (TmpS [4] in HexChars + ['x', 'X']) and (TmpS [5] in HexChars + ['x', 'X']) then begin
  477.         TmpS := 'PORTS';
  478.         if not IdxTbl. Search (@TmpS, J) then begin
  479.           WriteLn ('error searching for - ', TmpS);
  480.         end else begin
  481.           MinL := 0;
  482.           MatchFound := True;
  483.         end;
  484.       end;
  485.  
  486.       TmpW := PIndexEntry (IdxTbl. At (J))^.Ctx;
  487.  
  488.       if not MatchFound then begin
  489.         WriteLn (PString (At (0))^);
  490.         WriteLn ('error searching for - ', PString (Keywords. At (I))^);
  491.         WriteLn ('found match         - ', PIndexEntry (IdxTbl. At (J))^.PS^);
  492.         TmpW := 1;
  493.       end else
  494.         if MinL > 1 then begin
  495.           WriteLn (PString (At (0))^);
  496.           WriteLn ('approximate match to - ', PString (Keywords. At (I))^);
  497.           WriteLn ('is                   - ', PIndexEntry (IdxTbl. At (J))^.PS^);
  498.           TmpW := 1;
  499.         end;
  500.  
  501.       S. Write (TmpW, SizeOf (TmpW));
  502.     end;
  503. end;
  504.  
  505. { TIndexEntry = object (TObject) }
  506.  
  507. constructor TIndexEntry. Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
  508. begin
  509.   inherited Init;
  510.   PS := NewStr (S);
  511.   PS1 := NewStr (S1);
  512.   Ctx := ACtx;
  513.  
  514.   Topic := ATopic;
  515.   ATopic := nil;
  516.   Topic^.Store2Swap (SwapFile^);
  517.  
  518.   Indexed := IsIndexed;
  519. end;
  520.  
  521. procedure   TIndexEntry. Write (var S: TStream; const PrevStr: string);
  522. var
  523.   RptChars: Integer;
  524.   LengthCode: Byte;
  525. begin
  526.   if Length (PS^) > 31 then
  527.     WriteLn ('error 2');
  528.  
  529.   RptChars := 0;
  530.   while (RptChars < Length (PrevStr))
  531.   and   (PS^ [RptChars + 1] = PrevStr [RptChars + 1]) do
  532.     Inc (RptChars);
  533.  
  534.   if Length (PS^) = RptChars then
  535.     WriteLn ('error - duplicate index entry!');
  536.  
  537.   if RptChars > 7 then
  538.     RptChars := 7;
  539.  
  540.   LengthCode := (Length (PS^) - RptChars)
  541.               + (RptChars) shl 5;
  542.  
  543.   S. Write (LengthCode, SizeOf (LengthCode));
  544.   S. Write (PS^ [RptChars + 1],  Length (PS^) - RptChars);
  545.   S. Write (Ctx, SizeOf (Ctx));
  546. end;
  547.  
  548. procedure   TIndexEntry. AltWrite (var S: TStream);
  549. var B: Byte;
  550. begin
  551.   if Length (PS1^) > 36 then
  552.     WriteLn ('error 2A');
  553.  
  554.   S. Write (Ctx, SizeOf (Ctx));
  555.   S. Write (PS1^,  Length (PS1^) + 1);
  556.   B := 0;
  557.   S. Write (B, SizeOf (B));
  558. end;
  559.  
  560. destructor  TIndexEntry. Done;
  561. begin
  562.   DisposeStr (PS1);
  563.   DisposeStr (PS);
  564.   inherited Done;
  565. end;
  566.  
  567. { TIdxTbl = object (TSortedCollection) }
  568.  
  569. function  TIdxTbl. KeyOf (Item: Pointer): Pointer;
  570. begin
  571.   KeyOf := PIndexEntry (Item)^. PS;
  572. end;
  573.  
  574. function  TIdxTbl. Compare (Key1, Key2: Pointer): Integer;
  575. begin
  576.   if (Key1 = nil) or (StUpcase2 (PString (Key1)^) < StUpcase2 (PString (Key2)^)) then
  577.     Compare := -1
  578.   else
  579.     if (Key2 <> nil) and (StUpcase2 (PString (Key1)^) = StUpcase2 (PString (Key2)^)) then
  580.       Compare := 0
  581.     else
  582.       Compare := 1;
  583. end;
  584.  
  585. procedure TIdxTbl. SetCtxs;
  586. var I: Integer;
  587. begin
  588.   for I := 0 to Count - 1 do
  589.     PIndexEntry (At (I))^. Ctx := I + 1;
  590. end;
  591.  
  592. function  TIdxTbl. RealCount: Word;
  593. var Cnt: Word;
  594.   procedure AddOne (var X: TIndexEntry); far;
  595.   begin
  596.     if  (X. PS <> nil)
  597.     and (X. PS^ <> '')
  598.     and  X. Indexed then
  599.       Inc (Cnt);
  600.   end;
  601. begin
  602.   Cnt := 0;
  603.   ForEach (@AddOne);
  604.   RealCount := Cnt;
  605. end;
  606.  
  607. procedure TIdxTbl. Write (var S: TStream);
  608. var PrevStr: string;
  609.   procedure WriteOne (var X: TIndexEntry); far;
  610.   begin
  611.     if  (X. PS <> nil)
  612.     and (X. PS^ <> '')
  613.     and  X. Indexed then begin
  614.       X. Write (S, PrevStr);
  615.       PrevStr := X. PS^;
  616.     end;
  617.   end;
  618. begin
  619.   PrevStr := '';
  620.   ForEach (@WriteOne);
  621. end;
  622.  
  623. procedure TIdxTbl. AltWrite (var S: TStream; const GlobalAltName: string);
  624.   procedure WriteOne (var X: TIndexEntry); far;
  625.   begin
  626.     if  (X. PS1 <> nil)
  627.     and (X. PS1^ <> '')
  628.     and  X. Indexed then
  629.       X. AltWrite (S);
  630.   end;
  631. var
  632.   TmpW: Word;
  633.   TmpS: string;
  634. begin
  635.   TmpW := $FFFF;
  636.   S. Write (TmpW, SizeOf (TmpW));
  637.  
  638.   TmpS := GlobalAltName;
  639.   TmpS [Length (GlobalAltName) + 1] := #0;
  640.   S. Write (TmpS, Length (GlobalAltName) + 2);
  641.  
  642.   ForEach (@WriteOne);
  643. end;
  644.  
  645. procedure TIdxTbl. ReBuild (Level: Integer);
  646. var PrevStr: string;
  647.   procedure ReBuildOne (var X: TIndexEntry); far;
  648.   var CurStr: string;
  649.       I: Integer;
  650.   begin
  651.     if  (X. PS <> nil)
  652.     and (X. PS^ <> '')
  653.     and  X.Indexed then begin
  654.       if Length (X. PS^) > Level then begin
  655.         CurStr := Copy (X. PS^, 1, Level);
  656.  
  657.         for I := Length (CurStr) downto 2 do
  658.           if CurStr [I] = ' ' then begin
  659.             CurStr [0] := Chr (I - 1);
  660.             Break;
  661.           end;
  662.  
  663.         DisposeStr (X. PS);
  664.         X. PS := NewStr (CurStr);
  665.       end;
  666.  
  667.       PrevStr := X. PS^;
  668.     end;
  669.   end;
  670. begin
  671.   PrevStr := '';
  672.   ForEach (@ReBuildOne);
  673. end;
  674.  
  675. { THelpFile = object (TBufStream) }
  676.  
  677. constructor THelpFile.Init(FileName: FNameStr; Mode, Size: Word);
  678. begin
  679.   inherited Init (FileName, Mode, Size);
  680.   if Mode = stCreate then begin
  681.     Write (FileStamp, SizeOf (FileStamp));
  682.  
  683.     with FileStart do begin
  684.       with FileHdr_ do begin
  685.         RecType := RT_FileHeader;
  686.         RecLength := SizeOf (FileHdr);
  687.       end;
  688.       with FileHdr do begin
  689.         Options := 0;
  690.         MainIndexScreen := 02;
  691.         MaxScreenSize := High (MaxScreenSize) and (-256);
  692.         Height := 24;
  693.         Width := 80;
  694.         LeftMargin := 0;
  695.       end;
  696.  
  697.       with CompRec_ do begin
  698.         RecType := RT_Compression;
  699.         RecLength := SizeOf (CompRec);
  700.       end;
  701.       with CompRec do begin
  702.         CompType := CT_Nibble;
  703.         FillChar (CharTable, SizeOf (CharTable), 0);
  704.       end;
  705.     end;
  706.   end;
  707.  
  708.   New (CtxTbl);
  709.   if Mode = stCreate then begin
  710.     CtxTbl^. N := 0;
  711.   end;
  712.  
  713.   IdxTbl. Init (MaxCollectionSize, 0);
  714.   IdxTbl. Duplicates := True;
  715. end;
  716.  
  717. destructor  THelpFile.Done;
  718. var I: Integer;
  719.     R: TRecHdr;
  720.     TmpW: Word;
  721.     StartPos,
  722.     EndPos,
  723.     CtxStart: Longint;
  724.     CC: TCharCounter;
  725. begin
  726.   System. Write ('building compression record...                        '#13);
  727.   FillChar (CC, SizeOf (CC), 0);
  728.   for I := 0 to IdxTbl.Count - 1 do
  729.     PIndexEntry (IdxTbl. At (I))^.Topic^.UpdateCharCounter (CC);
  730.   CharCounter2CompRec (CC, FileStart. CompRec);
  731.   WriteLn ('building compression record... done');
  732.  
  733.   Write (FileStart, SizeOf (FileStart));
  734.  
  735.   CtxTbl^. N := IdxTbl. Count + 1;
  736.   CtxTbl^. T [0] := $FFFFFFFF;
  737.  
  738.   R. RecType := RT_Context;
  739.   R. RecLength := 2 + CtxTbl^. N * 3;
  740.   Write (R, SizeOf (R));
  741.   Write (CtxTbl^. N, SizeOf (CtxTbl^. N));
  742.   CtxStart := GetPos;
  743.   if CtxTbl^. N > 0 then
  744.     for I := 0 to CtxTbl^. N - 1 do
  745.       Write (CtxTbl^.T [I], 3);
  746.  
  747.   IdxTbl. SetCtxs;
  748.  
  749.   I := 31;
  750.   repeat
  751.     StartPos := GetPos;
  752.     R. RecType := RT_Index;
  753.     R. RecLength := 0;
  754.     Write (R, SizeOf (R));
  755.     TmpW := IdxTbl. RealCount;
  756.     Write (TmpW, 2);
  757.     IdxTbl. Write (Self);
  758.     EndPos := GetPos;
  759.     WriteLn ('index size - ', EndPos - StartPos - SizeOf (R));
  760.     Seek (StartPos);
  761.     if EndPos - StartPos - SizeOf (R) >= 65536 then begin
  762.       Dec (I);
  763.       WriteLn ('rebuilding index - level ', I);
  764.       IdxTbl. ReBuild (I);
  765.     end;
  766.   until EndPos - StartPos - SizeOf (R) < 65536;
  767.   R. RecLength := EndPos - StartPos - SizeOf (R);
  768.   Write (R, SizeOf (R));
  769.   Seek (EndPos);
  770.  
  771.   StartPos := GetPos;
  772.   R. RecType := RT_ScreenTags;
  773.   R. RecLength := 0;
  774.   Write (R, SizeOf (R));
  775.   IdxTbl. AltWrite (Self, 'Interrupt List');
  776.   EndPos := GetPos;
  777.   WriteLn ('alternative index size - ', EndPos - StartPos - SizeOf (R));
  778.   Seek (StartPos);
  779.   if EndPos - StartPos - SizeOf (R) >= 65536 then begin
  780.     WriteLn ('alternative index is too large.');
  781.     Halt (1);
  782.   end;
  783.   R. RecLength := EndPos - StartPos - SizeOf (R);
  784.   Write (R, SizeOf (R));
  785.   Seek (EndPos);
  786.  
  787.   for I := 0 to IdxTbl.Count - 1 do begin
  788.     CtxTbl^. T [PIndexEntry (IdxTbl. At (I))^.Ctx] := GetPos;
  789.     PIndexEntry (IdxTbl. At (I))^.Topic^.Write (Self, FileStart. CompRec);
  790.  
  791.     PIndexEntry (IdxTbl. At (I))^.Topic^.WriteKeywords (Self, IdxTbl);
  792.  
  793.     System. Write (I, #13);
  794.   end;
  795.  
  796.   Seek (CtxStart);
  797.   if CtxTbl^. N > 0 then
  798.     for I := 0 to CtxTbl^. N - 1 do
  799.       Write (CtxTbl^.T [I], 3);
  800.  
  801.   IdxTbl. Done;
  802.   if CtxTbl <> nil then
  803.     Dispose (CtxTbl);
  804.   inherited Done;
  805. end;
  806.  
  807. end.
  808.