{  (c) Copyright 1998,2000 Bernhard R. Link (2:2476/841.64;brl@gmx.de)
****************************************************************************
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************}
Unit mkSqIB; {MK Msg-Squish IDX-Buffer}
{$I platform.inc}
{$I mkglobal.inc}
{---------------------------------------------
 Bestandteil des JanPack-Editor-Projects
 ---------------------------------------------
 Plattformabhngier Teil Squish-Msgbase-
 Verwaltung.
 Stellt einen Buffer fr die SQI-Dateien zur
 Verfgung. Frher wurde da einfach nur Platz
 fr 5200 Record bereitgestellt und danach war
 Ende der Fahnenstange.
 ---------------------------------------------
 Diese Unit soll mehr Platz bereitstellen oder
 einen Fehler zurckliefern.
 ---------------------------------------------}
interface
uses {$IFDEF PPC_Virtual}Use32,{$ENDIF}
      aTypes,mkSqIdx,aString;

Type PSQI=^TSQI;
     TSQI=Record
          sqiOpened:Boolean;
          sqiFile:File;
          sqiAlloc:Word;
          sqIDX:sqIDXPtrType;
          MsgCount:longint;{Anzahl der Nachrichten}
          end;

Function SQI_Init(var sqi:PSQI):Boolean;
Procedure SQI_Done(var sqi:PSQI);
Function SQI_Open(sqi:Psqi;const fn:OpenString):word;
Procedure SQI_Close(sqi:PSqi);
Function SQI_ReAssign(Sqi:Psqi;sqdCount:Longint):Integer;
Procedure SQI_Free(var SqIAlloc:Word;var sqIdx:sqIdxPtrType);
Function SQI_OK(Sqi:PSQI):Boolean;
Function SQI_GetOfs(sqi:Psqi;i:TIDXNum):TFileOfs;
{-1, wenn ungltig, sonst Offset in Datei}
Function SQI_GetHash(sqi:Psqi;i:TIDXNum):uint4;
{0, wenn ungltig, sonst Offset in Datei}
Function SQI_FindMsgNum(sqi:Psqi;MsgNum:TUMID;var i:TIDXNum):Boolean;
{true, wenn Nachricht mit MsgNum gefunden oder wenn irgendeine Nachricht
gefunden, falls MsgNum=0}
Function SQI_FindAfterMsgNum(sqi:Psqi;MsgNum:TUMID;var i:TIDXNum):Boolean;
{true, wenn irgendeine Nachricht >MsgNum gefunden }

Procedure SQI_Delete(sqi:Psqi;IndexPos:TIdxNum);
Function SQI_Flush(sqi:Psqi):Integer;
Function SQI_GetHighest(sqi:Psqi):TUMID;
Function SQI_GetUMID(sqi:Psqi;i:TIDXNum):TUMID;
{Gibt -1, wenn ungltig, sonst die UMsgID}
Procedure SQI_Set(sqi:Psqi;i:TIDXNum;fOfs:TFileOfs;uid:TUMID;hashname:uint4);
Function SQI_Add(sqi:Psqi;fOfs:TFileOfs;uid:TUMID;hashname:uint4):Boolean;
Function SQI_Space(sqi:Psqi):Boolean;
{SQI_Space testet, ob ein folgendes SQI_Add true zurckliefern wrde.
SQI_Add darf nach einem erfolgreichen SQI_Space kein false zurckliefern}

const TestSQIIntegrity:Boolean=true;

implementation
uses UFiles{$IFDEF UseErrDlg},ErrDlg,StrRes{$ENDIF};

{$I-}

Procedure SQI_Close(sqi:PSqi);
begin
If sqi^.SqiOpened Then
  Close(SqI^.SqiFile);
If IoResult <> 0 Then;
SqI^.SqiOpened := False;
end;

Function SQI_Init(var sqi:PSQI):Boolean;
begin
New(sqi);
If sqi<>nil then
  begin
  SQI_INIT:=true;
  With sqi^ do
    begin
    sqiOpened:=false;
    sqiAlloc:=0;
    sqIDX:=nil
    end;
  end
 else
  SQI_INIT:=false;
end;

Procedure SQI_Done(var sqi:PSQI);
begin
If sqi=nil then
  exit;
If SqI^.SqiOpened Then
  Sqi_Close(sqi);
SQI_Free(SqI^.SqIAlloc,sqi^.sqIdx);
dispose(sqi);
sqi:=nil;
end;

Function SQI_Open(sqi:Psqi;const fn:OpenString):word;
begin
If Not SqI^.SqiOpened Then
  Begin
  Assign(SqI^.SqiFile, FN + '.sqi');
  FileMode := fmReadWrite + fmDenyNone;
  If not shReset(SqI^.SqiFile, SizeOf(SqIdxType)) Then
    Sqi_Open := UFilesError
   else
    begin
    SqI^.SqiOpened:=true;
    Sqi_Open := 0;
    end;
  end
 else
  begin
  Sqi_Open := 0;
  {$IFDEF UseErrDlg}
  InternalError($7307)
  {$ENDIF}
  end
end;

Function SQI_ReAssign(Sqi:Psqi;sqdCount:Longint):Integer;
  Procedure FreeAll;
  begin
  with sqi^ do
   begin
   If sqIdx<>nil then
     FreeMem(SqIdx, SqiAlloc * SizeOf(SqIdxType));
   sqIdx:=nil;
   SqiAlloc:=0;
   end
  end;
Var NumRead: Word;i:TIDXNum;
begin
SQI_ReAssign:=0;
With sqi^ do
  begin
  If SqiAlloc > 0 Then
    begin
    If SqIdx <> Nil Then
      FreeMem(SqIdx, SqiAlloc * SizeOf(SqIdxType));
    sqiAlloc:=0
    end;
  sqIdx:=nil;
  If not sqiOpened Then begin
    Sqi_ReAssign := 989;
    {$IFDEF UseErrDlg}
    InternalError($7306)
    {$ENDIF}
  end else begin
    {SqiOpened:=true; it's already true}
    MsgCount:=FileSize(sqiFile);
    writeLn(msgCount);
    If MsgCount>sqdCount then
      begin
      {ErrorBox(snWrongIDX);}
      MsgCount:=sqdCount;
      end;
    SqiAlloc := MsgCount + 100;
    If SqiAlloc > SqIdxArraySize Then
      If MsgCount > sqIdxArraySize then
         sqiAlloc:=0
        else
         SqiAlloc := SqIdxArraySize;
    If (sqiAlloc=0)or(MaxAvail<SqiAlloc * SizeOf(SqIdxType)) then
      sqIdx:=nil
     else
      GetMem(SqIdx, SqiAlloc * SizeOf(SqIdxType));
    If SqIdx = nil Then
      begin
      FreeAll;
      SQI_ReAssign := 999;
      end
     Else
      Begin
      Seek(SqiFile,0);
      If IoResult = 0 Then
        Begin
        If Not shRead(SqiFile, SqIdx^, MsgCount, NumRead) Then
          begin
          FreeAll;
          SQI_ReAssign := UFilesError
          end
         else
          If NumRead<>Msgcount then
            begin
            FreeAll;
            SQI_ReAssign:=991;
            end
           else
            begin
            If TestSQIIntegrity then
              For i:=2 to MsgCount do
                  if sqIdx^[i-1].UMsgID>=sqIdx^[i].UMsgID then
                     begin {The Items in SQI have to be sorted after UMsgID, anything else i a failure}
                     FreeAll;
                     SQI_ReAssign:=376;
                     exit;
                     end;
            SQI_ReAssign:=0;
            end;
        End
      Else
        begin
        FreeAll;
        SQI_ReAssign := 300;
        end
      End
    end
  end
end;

Procedure SQI_Free(var SqIAlloc:Word;var sqIdx:sqIdxPtrType);
begin
If SqIAlloc > 0 Then
  If SqIdx <> Nil Then
    FreeMem(SqIdx, SqiAlloc * SizeOf(SqIdxType));
end;

Function SQI_OK(SqI:PSQI):Boolean;
begin
SQI_OK:=(sqi<>nil)and(sqi^.sqIdx<>nil);
end;

Function SQI_FindMsgNum(sqi:Psqi;MsgNum:TUMID;var i:TIDXNum):Boolean;
var j,m:TIDXNum;
begin
With sqi^ do
  begin
  i:=1;
  If TestSQIIntegrity then {Falls wir uns sicher sind, dass es geht, nehmen wir binre Suche:}
    begin
    j:=MsgCount;
    While j>i do
      begin
      m:=(i+j)div 2;
      If MsgNum>SqIdx^[i].UMsgId then
          i:=m+1
         else
          j:=m-1
      end
    end
   else {Ansonsten ginge einfach zu hufig etwas daneben:}
     While ((i<=MsgCount)and(MsgNum{<>}>SqIdx^[i].UMsgId)) Do
       Inc(i);
  SQI_FindMsgNum:=(i<=MsgCount)and((MsgNum=0)or(MsgNum=SqIdx^[i].UMsgId));
  end;
end;

Function SQI_FindAfterMsgNum(sqi:Psqi;MsgNum:TUMID;var i:TIDXNum):Boolean;
begin
i := 1; (*sqiAlloc{SqInfo^.SqBase.NumMsg}*)
With sqi^ do
  begin
  While ((i<=MsgCount)and(MsgNum>=SqIdx^[i].UMsgId)) Do
    Inc(i);
  SQI_FindAfterMsgNum:=(i<=MsgCount);
  end;
end;


Function SQI_FindFrame(sqi:Psqi;frame:TFileOfs;var i:TIDXNum):Boolean;
begin
i := 1;
With sqi^ do
  begin
  While ((i<=MsgCount)and(frame<>SqIdx^[i].ofs)) Do
    Inc(i);
  SQI_FindFrame:=frame=SqIdx^[i].ofs;
  end;
end;


Function SQI_GetOfs(sqi:Psqi;i:TIDXNum):TFileOfs;
begin
If (i>=0)and(sqi<>nil)and(i<=sqi^.MsgCount) Then
  SQI_GetOfs:=sqi^.SqIdx^[i].Ofs
 else
  begin
  SQI_GetOfs:=-1;
  {$IFDEF UseErrDlg}
  InternalError($7305)
  {$ENDIF}
  end
end;

Procedure SQI_Delete(sqi:Psqi;IndexPos:TIdxNum);
var CurrMove:TIdxNum;
begin {mn ist zu diesen Zeitpunkt bereits erniedrigt,MsgCount noch nicht}
If sqi=nil then
  begin
  {$IFDEF UseErrDlg}
  InternalError($7303);
  {$ENDIF}
  Exit;
  end;
CurrMove:=IndexPos;
With sqi^ do
 If(IndexPos>0)and(IndexPos<=MsgCount) then{Damit nicht gelscht wird, was nicht existiert}
   begin
   While CurrMove<MsgCount Do
     Begin
     SqIdx^[CurrMove]:=SqIdx^[CurrMove + 1];
     Inc(CurrMove);
     End;
   dec(MsgCount);
   end
  {$IFDEF UseErrDlg}
  else
   InternalError($7300);
  {$ENDIF}
{ NumMove := SqInfo^.SqBase.NumMsg + 1 - IndexPos;
 NumMove := NumMove * SizeOf(SqIdxType);
 Move(SqIdx^[IndexPos + 1], SqIdx^[IndexPos], NumMove);}
end;

Function SQI_Flush(sqi:Psqi):Integer;
begin
SQI_Flush:=0;
If(Sqi=nil)or(sqi^.sqidx=nil) Then
  begin
  SQI_Flush := 999;
  {$IFDEF UseErrDlg}
  InternalError($7301)
  {$ENDIF}
  end
 else
  With sqi^ do
   Begin
   Seek(SqiFile, 0);
   Truncate(SqiFile);
   If IoResult = 0 Then
     begin
     If Not shWrite(SqiFile, SqIdx^, MsgCount) Then
       SQI_Flush:= UFilesError;
     end
    else
     SQI_Flush:=300;
   end;
end;

Function SQI_GetHighest(sqi:Psqi):TUMID;
Var
  i: TIdxNum;
  Tmp:TUMID;
Begin
If TestSQIIntegrity then
   SQI_GetHighest:=sqi^.SqIdx^[sqi^.MsgCount].UMsgId
  else
   begin
   Tmp := 0;
   i := 1;
   With sqi^ do
     While i <= Msgcount Do
       Begin
       If  SqIdx^[i].UMsgId > Tmp Then
         Tmp := SqIdx^[i].UMsgId;
       Inc(i)
       End;
   SQI_GetHighest:=Tmp
   end
end;

Function SQI_GetUMID(sqi:Psqi;i:TIDXNum):TUMID;
begin
If(sqi<>nil)and((i<=sqi^.MsgCount)and(i>0)) Then
  SQI_GetUMID := sqi^.SqIdx^[i].UMsgId
 Else
  begin
  SQI_GETUMID := -1;
  {$IFDEF UseErrDlg}
  InternalError($7302)
  {$ENDIF}
  end
end;

Function SQI_Space(sqi:Psqi):Boolean;
begin
SQI_Space:=(sqi^.MsgCount<sqi^.sqiAlloc)
end;

{$I beginudw.inc}

Procedure SQI_Set(sqi:Psqi;i:TIDXNum;fOfs:TFileOfs;
                 uid:TUMID;hashname:uint4);
begin
with sqi^.SqIdx^[i] do
  begin
  Ofs:=fOfs;
  UMsgId:=UID;
  Hash:=hashname
  end;
end;


Function SQI_Add(sqi:Psqi;fOfs:TFileOfs;uid:TUMID;hashname:uint4):Boolean;
begin
If sqi^.MsgCount>=sqi^.sqiAlloc then
  SQI_Add:=false
 else
  begin
  inc(sqi^.MsgCount);
  SQI_Add:=true;
  with sqi^.SqIdx^[sqi^.MsgCount] do
    begin
    Ofs:=fOfs;
    UMsgId:=UID;
    Hash:=hashname
    end;
  end;
end;

Function SQI_GetHash(sqi:Psqi;i:TIDXNum):uint4;
begin
If (i>=0)and(sqi<>nil)and(i<=sqi^.MsgCount) Then
  SQI_GetHash:=sqi^.SqIdx^[i].Hash
 else
  begin
  SQI_GetHash:=0;
  {$IFDEF UseErrDlg}
  InternalError($7304)
  {$ENDIF}
  end
end;


end.

