www.pudn.com > tp60src.zip > HELPSCRN.PAS


unit HelpScrn; 
 
{$O+,F+,S-,X+} 
 
interface 
 
uses Objects, HelpUtil; 
 
type 
 
  PHelpScreen = ^THelpScreen; 
  THelpScreen = object(TObject) 
    MaxIndex: Word; 
    MaxRow: Word; 
    HasExample: Boolean; 
    Buffer: PChar; 
    BufSize: Word; 
    constructor Init(ABuffer: PChar; ABufSize: Word); 
    function  Read(Index: Word): Boolean; virtual; 
    procedure GetRow(Row: Word; var Text: PChar; var Index: Word; 
      var Example: Boolean); virtual; 
    function  Format(Width: Word; var P; N: Word): Boolean; virtual; 
    procedure GetPos(Index: Word; var Row, Col: Integer; var Len: Word); virtual; 
    function  GetIndex(var S: string; var Len: Word): Word; virtual; 
    function  GetContext(Index: Word): Integer; virtual; 
    procedure GetExample(var StartPos, EndPos: TPos); virtual; 
    function  SearchRow(Row: Word): Integer; 
    function  SearchIndex(Index: Word): Integer; 
  end; 
 
  PHelpIndex = ^THelpIndex; 
  THelpIndex = object(THelpScreen) 
    BufPtr: PChar; 
    CurIndex: Word; 
    ContextNumber: Word; 
    IndexToken: string[38]; 
    CurLetter: Word; 
    function  Read(Index: Word): Boolean; virtual; 
    procedure GetRow(Row: Word; var Text: PChar; var Index: Word; 
      var Example: Boolean); virtual; 
    function  Format(Width: Word; var P; N: Word): Boolean; virtual; 
    procedure GetPos(Index: Word; var Row, Col: Integer; var Len: Word); virtual; 
    function  GetIndex(var S: string; var Len: Word): Word; virtual; 
    function  GetContext(Index: Word): Integer; virtual; 
    procedure GetExample(var StartPos, EndPos: TPos); virtual; 
    function  GetToken: Word; 
    function  TokenLength: Word; 
    procedure ReadLetter(Letter: Word); 
    procedure Track(Start, Target: Word); 
    procedure PositionTo(Index: Word); 
    procedure Parse; 
  end; 
 
  PHelpTopic = ^THelpTopic; 
  THelpTopic = object(THelpScreen) 
    TopicSize: Word; 
    BufPtr: PChar; 
    CurRow: Word; 
    CurIndex: Word; 
    InExample: Boolean; 
    constructor Init(ABuffer: PChar; ABufSize: Word); 
    function  Read(Index: Word): Boolean; virtual; 
    procedure GetRow(Row: Word; var Text: PChar; var Index: Word; 
      var Example: Boolean); virtual; 
    function  Format(Width: Word; var P; N: Word): Boolean; virtual; 
    procedure GetPos(Index: Word; var Row, Col: Integer; var Len: Word); virtual; 
    function  GetIndex(var S: string; var Len: Word): Word; virtual; 
    function  GetContext(Index: Word): Integer; virtual; 
    procedure GetExample(var StartPos, EndPos: TPos); virtual; 
    procedure CountRows; 
    procedure FindExample; 
    procedure Reset; 
    procedure GoBack(Amount: Word); 
    procedure GoForward(Amount: Word); 
    procedure GoRow(Row: Word); 
    procedure FindPos(Ofs: Word; var P: TPos); 
    function  FindChar(Num: Integer; C: Char): Word; 
  end; 
 
implementation 
 
uses HelpFile; 
 
type 
  PPosArray = ^TPosArray; 
  TPosArray = array[1..MaxCollectionSize] of ^TPos; 
 
const 
  ColumnCount: Word = 0; 
  ColumnWidth: Word = 0; 
  Master: array[0..26] of record 
    Offset, Size, StartIndex, StartRow: Word 
  end = ((), (), (), (), (), (), (), (), 
         (), (), (), (), (), (), (), (), 
         (), (), (), (), (), (), (), (), 
         (),(),()); 
  SaveMaxRow: Word = 0; 
 
procedure SortPos(A: PPosArray; N: Word); 
var 
  I, J: Word; 
  P: ^TPos; 
begin 
  if N > 1 then 
    for I := 1 to N - 1 do 
      for J := I + 1 to N do 
        if (A^[I]^.Row > A^[J]^.Row) or 
           (A^[I]^.Row = A^[J]^.Row) and (A^[I]^.Col > A^[J]^.Col) then 
        begin 
          P := A^[I]; 
          A^[I] := A^[J]; 
          A^[J] := P 
        end; 
end; 
 
constructor THelpScreen.Init(ABuffer: PChar; ABufSize: Word); 
begin 
  TObject.Init; 
  Buffer := ABuffer; 
  BufSize := ABufSize; 
  MaxIndex := 0; 
end; 
 
function THelpScreen.Read(Index: Word): Boolean; 
begin 
end; 
 
procedure THelpScreen.GetRow(Row: Word; var Text: PChar; var Index: Word; 
  var Example: Boolean); 
const 
  Empty: Char = #0; 
begin 
  if Row >= MaxRow then 
  begin 
    Text := @Empty; 
    Index := MaxIndex; 
    Example := False; 
  end; 
end; 
 
function THelpScreen.Format(Width: Word; var P; N: Word): Boolean; 
begin 
  Abstract; 
end; 
 
procedure THelpScreen.GetPos(Index: Word; var Row, Col: Integer; var Len: Word); 
begin 
  Abstract; 
end; 
 
function THelpScreen.GetIndex(var S: string; var Len: Word): Word; 
begin 
  Abstract; 
end; 
 
function THelpScreen.GetContext(Index: Word): Integer; 
begin 
  Abstract; 
end; 
 
procedure THelpScreen.GetExample(var StartPos, EndPos: TPos); 
begin 
  StartPos.Clear; 
  EndPos.Clear; 
end; 
 
function LetterNum(C: Char): Word; 
var 
  I: Integer; 
begin 
  I := Ord(UpCase(C)) - Ord('A') + 1; 
  if (I < 1) or (I > 26) then 
    I := 0; 
  LetterNum := I; 
end; 
 
function THelpScreen.SearchRow(Row: Word): Integer; 
var 
  I, J, K: Integer; 
  Found: Boolean; 
begin 
  if Row = 0 then 
    SearchRow := -1 
  else 
  begin 
    I := 0; 
    J := 26; 
    Found := False; 
    repeat 
      K := (J + I) shr 1; 
      if Master[K].StartRow > Row then 
        J := K - 1 
      else if (K < 26) and (Master[K+1].StartRow <= Row) then 
        I := K + 1 
      else 
        Found := True; 
    until Found; 
    SearchRow := K; 
  end; 
end; 
 
function THelpScreen.SearchIndex(Index: Word): Integer; 
var 
  I, J, K: Integer; 
  Found: Boolean; 
begin 
  I := 0; 
  J := 26; 
  Found := False; 
  repeat 
    K := (J + I) shr 1; 
    if Master[K].StartIndex > Index then 
      J := K - 1 
    else if (K < 26) and (Master[K+1].StartIndex <= Index) then 
      I := K + 1 
    else 
      Found := True; 
  until Found; 
  SearchIndex := K; 
end; 
 
function THelpIndex.GetToken: Word; assembler; 
asm 
        PUSH    DS 
        CLD 
        LDS     SI,Self 
        MOV     AX,[SI].CurIndex 
        CMP     AX,[SI].MaxIndex 
        JB      @@1 
        SUB     AX,AX 
        JMP     @@2 
@@1:    INC     [SI].CurIndex 
        MOV     AX,DS 
        MOV     ES,AX 
        LEA     DI,[SI].IndexToken+1 
        MOV     DX,DI 
        LDS     SI,[SI].BufPtr 
        SUB     AH,AH 
        LODSB 
        MOV     CX,AX 
        AND     CL,1FH 
        SHR     AL,1 
        SHR     AL,1 
        SHR     AL,1 
        SHR     AL,1 
        SHR     AL,1 
        ADD     DI,AX 
        REP     MOVSB 
        LODSW 
        LDS     BX,Self 
        MOV     [BX].ContextNumber,AX 
        MOV     [BX].BufPtr.Word[0],SI 
        XCHG    AX,DI 
        SUB     AX,DX 
        MOV     [BX].IndexToken.Byte,AL 
@@2:    POP     DS 
end; 
 
function THelpIndex.TokenLength: Word; assembler; 
asm 
        PUSH    DS 
        CLD 
        LDS     SI,Self 
        LDS     SI,[SI].BufPtr 
        SUB     AH,AH 
        LODSB 
        MOV     BX,AX 
        AND     BL,1FH 
        MOV     CL,5 
        SHR     AL,CL 
        ADD     AX,BX 
        POP     DS 
end; 
 
procedure THelpIndex.ReadLetter(Letter: Word); 
begin 
  if Letter <> CurLetter then 
    with Master[Letter] do 
    begin 
      ReadIndex(Buffer, Offset, Size); 
      CurIndex := StartIndex; 
      BufPtr := Buffer; 
      CurLetter := Letter; 
    end; 
end; 
 
procedure THelpIndex.Track(Start, Target: Word); 
begin 
  if (CurIndex > Target) or (CurIndex < Start) then 
  begin 
    BufPtr := Buffer; 
    CurIndex := Start 
  end; 
  while CurIndex < Target do 
    GetToken; 
end; 
 
procedure THelpIndex.PositionTo(Index: Word); 
var 
  Letter: Integer; 
begin 
  Letter := SearchIndex(Index); 
  ReadLetter(Letter); 
  with Master[Letter] do 
    Track(StartIndex, Index); 
end; 
 
procedure THelpIndex.Parse; 
var 
  MaxLength, CurOffset, BufOfs: Word; 
  TokenLen, Letter, CurRow, TokenCount, Rest, OldOfs, NewOfs: Word; 
begin 
  TokenCount := 0; 
  CurOffset := 2; 
  MaxLength := 0; 
  CurIndex := 1; 
  ReadIndex(Buffer, CurOffset, 4096); 
  NewOfs := CurOffset; 
  BufPtr := Buffer; 
  BufOfs := PtrRec(BufPtr).Ofs; 
  for Letter := 0 to 26 do 
    with Master[Letter] do 
    begin 
      Offset := CurOffset; 
      StartIndex := TokenCount; 
      OldOfs := BufOfs; 
      Dec(CurIndex); 
      PtrRec(BufPtr).Ofs := BufOfs; 
      Rest := 0; 
      TokenLen := GetToken; 
      while (TokenLen > 0) and (LetterNum(IndexToken[1]) = Letter) do 
      begin 
        if MaxLength < TokenLen then 
          MaxLength := TokenLen; 
        Inc(TokenCount); 
        BufOfs := PtrRec(BufPtr).Ofs; 
        if BufOfs - PtrRec(Buffer).Ofs > 4016 then 
        begin 
          Rest := BufOfs - PtrRec(Buffer).Ofs; 
          NewOfs := NewOfs + Rest; 
          ReadIndex(Buffer, NewOfs, 4096); 
          BufPtr := Buffer; 
          BufOfs := PtrRec(Buffer).Ofs; 
        end; 
        TokenLen := GetToken; 
      end; 
      Size := BufOfs + Rest - OldOfs; 
      CurOffset := Offset + Size; 
    end; 
  if MaxLength = 0 then 
    MaxLength := 38; 
  ColumnCount := 76 div MaxLength; 
  if ColumnCount = 0 then 
    ColumnCount := 1; 
  if ColumnCount > 4 then 
    ColumnCount := 4; 
  ColumnWidth := 76 div ColumnCount; 
  CurRow := 1; 
  for Letter := 0 to 25 do 
    with Master[Letter] do 
    begin 
      StartRow := CurRow; 
      CurRow := CurRow + 3 + (Master[Letter+1].StartIndex - StartIndex + 
        ColumnCount - 1) div ColumnCount; 
    end; 
  Master[26].StartRow := CurRow; 
  MaxRow := CurRow + 3 + (MaxIndex - Master[26].StartIndex + 
    ColumnCount - 1) div ColumnCount; 
  SaveMaxRow := MaxRow; 
end; 
 
function THelpIndex.Read(Index: Word): Boolean; 
begin 
  Read := False; 
  if ReadIndex(Buffer, 0, 2) <> 0 then 
  begin 
    Read := True; 
    MaxIndex := PWordArray(Buffer)^[0]; 
    HasExample := False; 
    if Master[0].Offset = 0 then 
      Parse 
    else 
      MaxRow := SaveMaxRow; 
    CurLetter := 255; 
  end; 
end; 
 
procedure THelpIndex.GetRow(Row: Word; var Text: PChar; var Index: Word; 
  var Example: Boolean); 
 
procedure MakeBold(Dest, Src: string; Width: Word); assembler; 
asm 
        PUSH    DS 
        CLD 
        LES     DI,Dest 
        LDS     SI,Src 
        MOV     AL,ES:[DI] 
        SUB     AH,AH 
        ADD     DI,AX 
        LODSB 
        XCHG    AX,CX 
        MOV     AX,Width 
        SUB     AX,CX 
        XCHG    AX,DX 
        MOV     AL,2 
        STOSB 
        REP     MOVSB 
        STOSB 
        MOV     CX,DX 
        MOV     AL,' ' 
        REP     STOSB 
        SUB     AL,AL 
        STOSB 
        MOV     AX,Dest.Word[0] 
        XCHG    AX,DI 
        SUB     AX,DI 
        DEC     AX 
        MOV     ES:[DI],AL 
        POP     DS 
end; 
 
const 
  S: string[87] = ''; 
var 
  Letter, R: Integer; 
  I: Word; 
begin 
  THelpScreen.GetRow(Row, Text, Index, Example); 
  if Row < MaxRow then 
  begin 
    Index := 0; 
    Example := False; 
    S := #0; 
    Text := @S[1]; 
    Letter := SearchRow(Row); 
    if Letter < 0 then 
      S := 'Turbo Help Index'#0 
    else 
      with Master[Letter] do 
      begin 
        ReadLetter(Letter); 
        R := Row - StartRow - 3; 
        if R < 0 then 
        begin 
          Index := StartIndex; 
          if (R = -2) and (Letter > 0) then 
            S := Chr(Letter + Ord('A') - 1) + #0; 
        end else 
        begin 
          I := StartIndex + R * ColumnCount; 
          Index := I; 
          Track(StartIndex, I); 
          if Letter = 26 then 
            I := MaxIndex - I 
          else 
            I := Master[Letter+1].StartIndex - I; 
          if I > ColumnCount then 
            I := ColumnCount; 
          while I > 0 do 
          begin 
            GetToken; 
            MakeBold(S, IndexToken, ColumnWidth); 
            Dec(I); 
          end; 
        end; 
      end; 
  end; 
end; 
 
function THelpIndex.Format(Width: Word; var P; N: Word): Boolean; 
begin 
  Format := True; 
end; 
 
procedure THelpIndex.GetPos(Index: Word; var Row, Col: Integer; var Len: Word); 
var 
  Letter: Integer; 
begin 
  Letter := SearchIndex(Index); 
  with Master[Letter] do 
  begin 
    Row := StartRow + 3 + (Index - StartIndex) div ColumnCount; 
    Col := (Index - StartIndex) mod ColumnCount * ColumnWidth + 1; 
    PositionTo(Index); 
    Len := TokenLength; 
  end; 
end; 
 
function THelpIndex.GetIndex(var S: string; var Len: Word): Word; 
 
function StrCmp(S1, S2: string): Boolean; assembler; 
asm 
        PUSH    DS 
        CLD 
        LDS     SI,S2 
        LES     DI,S1 
        MOV     CL,ES:[DI] 
        CMPSB 
        JB      @@3 
        SUB     CH,CH 
@@1:    LODSB 
        CMP     AL,'a' 
        JB      @@2 
        CMP     AL,'z' 
        JA      @@2 
        AND     AL,0DFH 
@@2:    SCASB 
        LOOPZ   @@1 
        JNZ     @@3 
        MOV     AX,1 
        JMP     @@4 
@@3:    SUB     AX,AX 
@@4:    POP     DS 
end; 
 
var 
  Letter: Integer; 
  Max, Index: Word; 
  Found: Boolean; 
begin 
  GetIndex := $FFFE; 
  Len := 0; 
  if Length(S) > 0 then 
  begin 
    Letter := LetterNum(S[1]); 
    with Master[Letter] do 
    begin 
      ReadLetter(Letter); 
      Track(StartIndex, StartIndex); 
      if Letter = 26 then 
        Max := MaxIndex 
      else 
        Max := Master[Letter+1].StartIndex; 
      Index := StartIndex; 
      Found := False; 
      while (Index < Max) and not Found do 
      begin 
        GetToken; 
        if StrCmp(S, IndexToken) then 
          Found := True 
        else 
          Inc(Index); 
      end; 
      if Found then 
      begin 
        Len := Length(S); 
        GetIndex := Index 
      end; 
    end; 
  end else 
    GetIndex := 0; 
end; 
 
function THelpIndex.GetContext(Index: Word): Integer; 
begin 
  PositionTo(Index); 
  GetToken; 
  GetContext := ContextNumber; 
end; 
 
procedure THelpIndex.GetExample(var StartPos, EndPos: TPos); 
begin 
  THelpScreen.GetExample(StartPos, EndPos); 
end; 
 
constructor THelpTopic.Init(ABuffer: PChar; ABufSize: Word); 
begin 
  THelpScreen.Init(ABuffer, ABufSize); 
  TopicSize := 0; 
end; 
 
function THelpTopic.Read(Index: Word): Boolean; 
begin 
  Read := ReadTopic(Index, Buffer, BufSize, TopicSize, MaxIndex); 
  Reset; 
  CountRows; 
  FindExample; 
end; 
 
procedure THelpTopic.CountRows; assembler; 
asm 
        PUSH    DS 
        LDS     SI,Self 
        MOV     CX,[SI].TopicSize 
        LES     DI,[SI].Buffer 
        SUB     AX,AX 
        SUB     BX,BX 
        CLD 
@@1:    JCXZ    @@2 
        REPNZ   SCASB 
        INC     BX 
        JMP     @@1 
@@2:    MOV     [SI].MaxRow,BX 
        POP     DS 
end; 
 
procedure THelpTopic.FindExample; assembler; 
asm 
        PUSH    DS 
        LDS     SI,Self 
        MOV     CX,[SI].TopicSize 
        LES     DI,[SI].Buffer 
        MOV     AL,5 
        SUB     BX,BX 
        CLD 
        JCXZ    @@1 
        REPNE   SCASB 
        JNE     @@1 
        INC     BX 
@@1:    MOV     [SI].HasExample,bl 
        POP     DS 
end; 
 
procedure THelpTopic.Reset; 
begin 
  BufPtr := Buffer; 
  CurRow := 0; 
  CurIndex := 0; 
  InExample := False; 
end; 
 
procedure THelpTopic.GoBack(Amount: Word); 
begin 
  if CurRow <= Amount then 
    Reset 
  else 
    asm 
        PUSH    DS 
        LDS     SI,Self 
        LES     DI,[SI].BufPtr 
        SUB     AH,AH 
        SUB     DX,DX 
        MOV     BX,Amount 
        STD 
        INC     BX 
        DEC     DI 
        DEC     DI 
        JMP     @@7 
@@1:    MOV     CX,0FFFFH 
        SUB     AL,AL 
        REPNZ   SCASB 
        NOT     CX 
        PUSH    DI 
        ADD     DI,CX 
        DEC     CX 
        JCXZ    @@6 
        MOV     AL,2 
        PUSH    CX 
        PUSH    DI 
        JMP     @@3 
@@2:    INC     DX 
@@3:    REPNE   SCASB 
        JE      @@2 
        MOV     AL,5 
        POP     DI 
        POP     CX 
        JMP     @@5 
@@4:    INC     AH 
@@5:    REPNE   SCASB 
        JE      @@4 
@@6:    POP     DI 
@@7:    DEC     BX 
        JNZ     @@1 
        AND     AH,1 
        XOR     [SI].InExample,AH 
        SHR     DX,1 
        SUB     [SI].CurIndex,DX 
        INC     DI 
        INC     DI 
        MOV     [SI].BufPtr.Word[0],DI 
        MOV     AX,Amount 
        SUB     [SI].CurRow,AX 
        POP     DS 
        CLD 
    end; 
end; 
 
procedure THelpTopic.GoForward(Amount: Word); 
begin 
  if CurRow + Amount >= MaxRow then 
    Amount := MaxRow - CurRow - 1; 
  asm 
        PUSH    DS 
        LDS     SI,Self 
        LES     DI,[SI].BufPtr 
        SUB     AH,AH 
        SUB     DX,DX 
        MOV     BX,Amount 
        CLD 
        INC     BX 
        JMP     @@7 
@@1:    MOV     CX,0FFFFH 
        SUB     AL,AL 
        REPNZ   SCASB 
        NOT     CX 
        PUSH    DI 
        SUB     DI,CX 
        DEC     CX 
        JCXZ    @@6 
        MOV     AL,2 
        PUSH    CX 
        PUSH    DI 
        JMP     @@3 
@@2:    INC     DX 
@@3:    REPNE   SCASB 
        JE      @@2 
        MOV     AL,5 
        POP     DI 
        POP     CX 
        JMP     @@5 
@@4:    INC     AH 
@@5:    REPNE   SCASB 
        JE      @@4 
@@6:    POP     DI 
@@7:    DEC     BX 
        JNZ     @@1 
        AND     AH,1 
        XOR     [SI].InExample,AH 
        SHR     DX,1 
        ADD     [SI].CurIndex,DX 
        MOV     [SI].BufPtr.Word[0],DI 
        MOV     AX,Amount 
        ADD     [SI].CurRow,AX 
        POP     DS 
  end; 
end; 
 
procedure THelpTopic.GoRow(Row: Word); 
begin 
  if Row < CurRow then 
    if Row < CurRow shr 1 then 
    begin 
      Reset; 
      GoForward(Row) 
    end else 
      GoBack(CurRow - Row) 
  else if Row > CurRow then 
    GoForward(Row - CurRow); 
end; 
 
procedure THelpTopic.GetRow(Row: Word; var Text: PChar;var Index: Word; 
  var Example: Boolean); 
begin 
  THelpScreen.GetRow(Row, Text, Index, Example); 
  if Row < MaxRow then 
  begin 
    GoRow(Row); 
    Text := BufPtr; 
    Index := CurIndex; 
    Example := InExample; 
  end; 
end; 
 
function THelpTopic.Format(Width: Word; var P; N: Word): Boolean; assembler; 
var 
  SaveSP, IndexStart, Row: Word; 
  RowLen: byte; 
  NewMaxRow: Word; 
  HasControlChars: Boolean; 
  WordBuf: string[79]; 
  WordLen: byte; 
  RowEnd: Word; 
  CurPosPtr: PPosArray; 
  TargetRow: Word; 
  TargetCol: Byte; 
  InKeyword: byte; 
asm 
        PUSH    DS 
        MOV     SaveSP,SP 
        PUSH    P.Word[2] 
        PUSH    P.Word[0] 
        PUSH    N 
        CALL    SortPos 
        SUB     AX,AX 
        MOV     Row,AX 
        MOV     NewMaxRow,AX 
        MOV     HasControlChars,AL 
        SUB     Width,1 
        LES     AX,P 
        MOV     CurPosPtr.Word[2],ES 
        SUB     AX,4 
        MOV     CurPosPtr.Word[0],AX 
        LDS     SI,Self 
        LES     DI,[SI].Buffer 
        MOV     AX,DI 
        MOV     CX,[SI].TopicSize 
        ADD     AX,CX 
        DEC     AX 
        ADD     DI,[SI].BufSize 
        SUB     DI,[SI].MaxIndex 
        SUB     DI,[SI].MaxIndex 
        MOV     IndexStart,DI 
        DEC     DI 
        XCHG    AX,SI 
        PUSH    ES 
        POP     DS 
        STD 
        REP     MOVSB 
        CLD 
        XCHG    SI,DI 
        INC     SI 
        INC     DI 
        CALL    @@19 
@@1:    CMP     SI,IndexStart 
        JAE     @@30 
@@2:    MOV     AL,[SI] 
        AND     AL,AL 
        JZ      @@3 
        CMP     AL,' ' 
        JNE     @@6 
@@3:    CMP     HasControlChars,0 
        JE      @@4 
        CALL    @@18 
@@4:    MOV     AX,Row 
        CMP     AX,TargetRow 
        JNE     @@5 
        PUSH    DS 
        PUSH    SI 
        LDS     SI,CurPosPtr 
        LDS     SI,[SI] 
        MOV     AX,NewMaxRow 
        MOV     [SI].TPos.Row,AX 
        POP     SI 
        POP     DS 
        CALL    @@19 
        JMP     @@4 
@@5:    XCHG    SI,DI 
        SUB     AX,AX 
        MOV     CX,0FFFFh 
        REPNZ   SCASB 
        NOT     CX 
        SUB     DI,CX 
        XCHG    SI,DI 
        REP     MOVSB 
        INC     NewMaxRow 
        JMP     @@16 
@@6:    MOV     RowLen,1 
@@7:    MOV     AX,Row 
        CMP     AX,TargetRow 
        JNE     @@13 
@@8:    CMP     BYTE PTR [SI],0 
        JE      @@11 
        MOV     AL,RowLen 
        CMP     AL,1 
        JE      @@9 
        CMP     AL,TargetCol 
        JA      @@11 
@@9:    CALL    @@21 
        MOV     AL,HasControlChars 
        AND     AL,AL 
        JZ      @@10 
        ADD     AL,WordLen 
        CBW 
        CMP     AX,Width 
        JBE     @@10 
        CALL    @@18 
@@10:   CALL    @@28 
        JMP     @@8 
@@11:   PUSH    DS 
        PUSH    SI 
        LDS     SI,CurPosPtr 
        LDS     SI,[SI] 
        MOV     AX,NewMaxRow 
        MOV     [SI].TPos.Row,AX 
        MOV     AL,TargetCol 
        CMP     AL,RowLen 
        JBE     @@12 
        MOV     RowLen,AL 
@@12:   MOV     AL,HasControlChars 
        ADD     AL,1 
        SUB     AL,RowLen 
        ADD     AL,TargetCol 
        MOV     [SI].TPos.Col,AL 
        POP     SI 
        POP     DS 
        CALL    @@19 
        JMP     @@7 
@@13:   CMP     BYTE PTR [SI],0 
        JE      @@15 
        CALL    @@21 
        MOV     AL,HasControlChars 
        AND     AL,AL 
        JZ      @@14 
        ADD     AL,WordLen 
        CBW 
        CMP     AX,Width 
        JBE     @@14 
        CALL    @@18 
@@14:   CALL    @@28 
        JMP     @@13 
@@15:   INC     SI 
@@16:   INC     Row 
        JMP     @@1 
@@17:   MOV     SP,SaveSP 
        SUB     AX,AX 
        JMP     @@32 
@@18:   SUB     AX,AX 
        STOSB 
        CMP     DI,SI 
        JAE     @@17 
        MOV     HasControlChars,AL 
        INC     NewMaxRow 
        RETN 
@@19:   MOV     AX,N 
        AND     AX,AX 
        MOV     AX,-1 
        JZ      @@20 
        DEC     N 
        ADD     CurPosPtr.Word[0],4 
        PUSH    DS 
        PUSH    SI 
        LDS     SI,CurPosPtr 
        LDS     SI,[SI] 
        MOV     AL,[SI].TPos.Col 
        MOV     TargetCol,AL 
        MOV     AX,[SI].TPos.Row 
        POP     SI 
        POP     DS 
@@20:   MOV     TargetRow,AX 
        RETN 
@@21:   PUSH    ES 
        PUSH    DI 
        SUB     AX,AX 
        MOV     WordLen,AL 
        MOV     InKeyword,AL 
        MOV     AX,SS 
        MOV     ES,AX 
        LEA     DI,WordBuf 
@@22:   MOV     AL,[SI] 
        AND     AL,AL 
        JZ      @@25 
        CMP     AL,' ' 
        JNE     @@23 
        TEST    InKeyword,1 
        JZ      @@26 
@@23:   INC     SI 
        STOSB 
        CMP     AL,7 
        JB      @@24 
        INC     WordLen 
        INC     RowLen 
        JMP     @@22 
@@24:   CMP     AL,2 
        JNE     @@22 
        XOR     InKeyword,1 
        JMP     @@22 
@@25:   MOV     AL,' ' 
        STOSB 
        INC     RowLen 
        JMP     @@27 
@@26:   MOV     AL,' ' 
        STOSB 
        INC     SI 
        INC     RowLen 
        CMP     [SI],AL 
        JE      @@26 
@@27:   MOV     RowEnd,DI 
        POP     DI 
        POP     ES 
        RETN 
@@28:   PUSH    DS 
        PUSH    SI 
        MOV     AX,SS 
        MOV     DS,AX 
        LEA     SI,WordBuf 
        MOV     CX,RowEnd 
        SUB     CX,SI 
@@29:   LODSB 
        STOSB 
        CMP     AL,7 
        SBB     HasControlChars,-1 
        LOOP    @@29 
        POP     SI 
        POP     DS 
        RETN 
@@30:   CMP     HasControlChars,0 
        JE      @@31 
        CALL    @@18 
@@31:   LDS     SI,Self 
        SUB     DI,[SI].Buffer.Word[0] 
        MOV     [SI].TopicSize,DI 
        MOV     AX,NewMaxRow 
        MOV     [SI].MaxRow,AX 
        POP     AX 
        PUSH    DS 
        PUSH    SI 
        MOV     DS,AX 
        CALL    Reset 
        PUSH    DS 
        MOV     AX,1 
@@32:   POP     DS 
end; 
 
procedure THelpTopic.GetPos(Index: Word; var Row, Col: Integer; var Len: Word); 
begin 
  if Index >= MaxIndex then 
    Index := MaxIndex - 1; 
  while (CurIndex <= Index) and (CurRow < MaxRow - 1) do 
    GoForward(1); 
  while CurIndex > Index do 
    GoBack(1); 
  Row := CurRow; 
  asm 
        PUSH    DS 
        LDS     SI,Self 
        MOV     CX,Index 
        SUB     CX,[SI].CurIndex 
        SHL     CX,1 
        INC     CX 
        LDS     SI,[SI].BufPtr 
        MOV     DX,1 
@@1:    LODSB 
        INC     DX 
        CMP     AL,7 
        JAE     @@1 
        DEC     DX 
        CMP     AL,2 
        JNE     @@1 
        LOOP    @@1 
@@2:    LODSB 
        INC     CX 
        CMP     AL,2 
        JNE     @@2 
        DEC     CX 
        LDS     SI,Col 
        MOV     [SI],DX 
        LDS     SI,Len 
        MOV     [SI],CX 
        POP     DS 
  end; 
end; 
 
function THelpTopic.GetIndex(var S: string; var Len: Word): Word; assembler; 
asm 
        PUSH    DS 
        LDS     SI,Self 
        LES     DI,[SI].Buffer 
        MOV     CX,0FFFFh 
        MOV     DX,[SI].MaxIndex 
        MOV     AL,2 
        MOV     DS,S.Word[2] 
        INC     DX 
        CLD 
@@1:    DEC     DX 
        JZ      @@7 
        REPNE   SCASB 
        JNZ     @@7 
        MOV     SI,S.Word[0] 
        MOV     BH,[SI] 
        INC     SI 
        SUB     BL,BL 
@@2:    MOV     AH,ES:[DI] 
        INC     DI 
        INC     BX 
        CMP     AH,' ' 
        JE      @@2 
        DEC     BX 
        INC     BH 
        JMP     @@5 
@@3:    CMP     AH,'a' 
        JB      @@4 
        CMP     AH,'z' 
        JA      @@4 
        AND     AH,0DFH 
@@4:    CMP     AH,[SI] 
        JNE     @@6 
        INC     SI 
        MOV     AH,ES:[DI] 
        INC     DI 
        INC     BX 
@@5:    DEC     BH 
        JNZ     @@3 
        LDS     SI,Self 
        MOV     AX,[SI].MaxIndex 
        SUB     AX,DX 
        LDS     SI,Len 
        SUB     BH,BH 
        MOV     [SI],BX 
        JMP     @@8 
@@6:    CMP     AH,AL 
        JE      @@1 
        REPNE   SCASB 
        JZ      @@1 
@@7:    MOV     AX,0FFFEH 
@@8:    POP     DS 
end; 
 
function THelpTopic.GetContext(Index: Word): Integer; assembler; 
asm 
        PUSH    DS 
        LDS     SI,Self 
        MOV     AX,[SI].MaxIndex 
        MOV     BX,Index 
        CMP     BX,AX 
        JB      @@1 
        SUB     AX,AX 
        JMP     @@2 
@@1:    LES     DI,[SI].Buffer 
        ADD     DI,[SI].BufSize 
        SHL     AX,1 
        SUB     DI,AX 
        SHL     BX,1 
        MOV     AX,ES:[BX+DI] 
@@2:    POP     DS 
end; 
 
procedure THelpTopic.FindPos(Ofs: Word; var P: TPos); 
begin 
  if Ofs = $FFFF then 
    with P do 
    begin 
      Row := 0; 
      Col := 0 
    end else 
      asm 
        PUSH    DS 
        STD 
        LDS     SI,Self 
        LES     DI,[SI].Buffer 
        MOV     AX,Ofs 
        XCHG    AX,DI 
        SUB     AX,DI 
        NEG     AX 
        XCHG    AX,CX 
        SUB     BX,BX 
        MOV     DL,1 
        JCXZ    @@3 
@@1:    DEC     DI 
        MOV     AL,ES:[DI] 
        CMP     AL,7 
        SBB     DL,-1 
        AND     AL,AL 
        LOOPNZ  @@1 
        JNZ     @@3 
        INC     CX 
        SUB     AL,AL 
@@2:    JCXZ    @@3 
        REPNZ   SCASB 
        JNZ     @@3 
        INC     BX 
        JMP     @@2 
@@3:    LDS     SI,P 
        MOV     [SI].TPos.Col,DL 
        MOV     [SI].TPos.Row,BX 
        CLD 
        POP     DS 
  end; 
end; 
 
function THelpTopic.FindChar(Num: Integer; C: Char): Word; assembler; 
asm 
        PUSH    DS 
        CLD 
        LDS     SI,Self 
        LES     DI,[SI].Buffer 
        MOV     CX,[SI].TopicSize 
        MOV     AL,C 
        MOV     DX,Num 
        AND     DX,DX 
        JZ      @@2 
@@1:    JCXZ    @@2 
        REPNE   SCASB 
        JZ      @@3 
@@2:    MOV     AX,0FFFFH 
        JMP     @@4 
@@3:    DEC     DX 
        JNZ     @@1 
        XCHG    AX,DI 
        DEC     AX 
@@4:    POP     DS 
end; 
 
procedure THelpTopic.GetExample(var StartPos, EndPos: TPos); 
begin 
  FindPos(FindChar(1, #5), StartPos); 
  FindPos(FindChar(2, #5), EndPos); 
end; 
 
end.