⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 awkermit.pas

📁 测试用例
💻 PAS
📖 第 1 页 / 共 5 页
字号:
  end;

  function kpPrevSeq(P : PProtocolData; I : Integer) : Integer;
    {-Decrement I to previous slot, accounting for current table size}
  begin
    with P^ do begin
      Dec(I);
      if I = 0 then
        I := kTableSize;
      kpPrevSeq := I;
    end;
  end;

  function kpTableFull(P : PProtocolData) : Bool;
    {-Returns True if the send table is full}
  begin
    with P^ do
      kpTableFull := kInfoTable[kpNextSeq(P, kTableHead)].InUse;
  end;

  function kpPacketsOutstanding(P : PProtocolData) : Bool;
    {-True if there are unacked packets in the table}
  var
    I : Integer;
  begin
    with P^ do begin
      kpPacketsOutstanding := True;
      for I := 1 to kTableSize do
        if kInfoTable[I].InUse then
          Exit;
      kpPacketsOutstanding := False;
    end;
  end;

  function kpGetOldestSequence(P : PProtocolData) : Integer;
  var
    I, Oldest : Integer;
  begin
    Oldest := MaxInt;
    with P^ do begin
      for I := 1 to kTableSize do begin
        if kInfoTable[I].InUse and (kInfoTable[I].Seq < Oldest) then
          Oldest := I;
      end;
      if Oldest = MaxInt then
        Result := -1
      else
        Result := kInfoTable[Oldest].Seq;
    end;
  end;                                                               

  function kpSeqInTable(P : PProtocolData; CurSeq : Integer) : Integer;
    {-Return the position in the table of CurSeq, or -1 of not found}
  var
    I : Integer;
  begin
    with P^ do begin
      kpSeqInTable := -1;
      for I := 1 to kTableSize do
        if kInfoTable[I].Seq = CurSeq then begin
          kpSeqInTable := I;
          Exit;
        end;
    end;
  end;

  procedure kpGotAck(P : PProtocolData; CurSeq : Cardinal);
    {-Note ACK for block number CurSeq}
  var
    I : Integer;
  begin
    with P^ do begin
      I := kpSeqInTable(P, CurSeq);
      if I <> - 1 then 
        kInfoTable[I].InUse := False;
    end;
  end;

  function kpWindowsUsed(P : PProtocolData) : Byte;
    {-Return number of window slots in use}
  var
    I : Integer;
    Cnt : Cardinal;
  begin
    with P^ do begin
      if not kpPacketsOutstanding(P) then begin
        kpWindowsUsed := 0;
        Exit;
      end;

      Cnt := 0;
      for I := 1 to kTableSize do
        if kInfoTable[I].InUse then
          Inc(Cnt);

      kpWindowsUsed := Cnt;
    end;
  end;

  procedure kpWritePacket(P : PProtocolData; Index : Byte);
    {-Expand and write the packet from table slot Index}
  var
    TIndex : Cardinal;
    WIndex : Cardinal;
    LastIndex : Cardinal;
    RepeatCnt : Cardinal;
    Free : Cardinal;
    Left : Cardinal;
    C : Char;
    Failed : Bool;

    procedure WriteBlock;
    begin
      with P^ do begin
        Failed := apWriteProtocolBlock(P, kWorkBlock^, SizeOf(kWorkBlock^));
        Inc(aFileOfs, SizeOf(kWorkBlock^));
        WIndex := 1;
        Free := SizeOf(kWorkBlock^);
      end;
    end;

  begin
    with P^ do begin
      {Set starting indexes}
      TIndex := Cardinal(Index-1)*aBlockLen;
      LastIndex := Integer(TIndex)+kInfoTable[Index].Len;            
      WIndex := 1;

      {Loop through this block in kDataTable...}
      Failed := False;
      repeat
        {Get a character with escaping already translated}
        kpGetDataChar(P, C, TIndex, RepeatCnt);

        if RepeatCnt = 1 then begin
          {Single char, just add it to WorkBlock}
          kWorkBlock^[WIndex] := C;
          Inc(WIndex);
        end else begin
          {Repeating char, start filling aDataBlock(s)}
          Free := SizeOf(kWorkBlock^)-(WIndex-1);
          Left := RepeatCnt;
          repeat
            if Free >= Left then begin
              FillChar(kWorkBlock^[WIndex], Left, C);
              Inc(WIndex, Left);
              Left := 0;
            end else begin
              FillChar(kWorkBlock^[WIndex], Free, C);
              Inc(WIndex, Free);
              Dec(Left, Free);
            end;

            {Flush WorkBlock if it fills}
            if WIndex = SizeOf(kWorkBlock^)+1 then
              WriteBlock;
          until (Left = 0) or Failed;
        end;

        {Flush WorkBlock if it fills}
        if WIndex = SizeOf(kWorkBlock^)+1 then
          WriteBlock;

      until (TIndex = LastIndex) or Failed;

      {Commit last, or only, block}
      if WIndex <> 1 then begin
        Failed := apWriteProtocolBlock(P, kWorkBlock^, WIndex-1);
        Inc(aFileOfs, WIndex-1);
      end;
    end;
  end;

  function kpSeqGreater(P : PProtocolData; Seq1, Seq2 : Byte) : Bool;
    {-Return True if Seq is greater than Seq2, accounting for wrap at 64}
  var
    I : Integer;
  begin
    with P^ do begin
      I := Seq1 - Seq2;
      if I > 0 then
        kpSeqGreater := (I < 32)
      else
        kpSeqGreater := (Abs(I) > 32);
    end;
  end;

  function kpLoSeq(P : PProtocolData) : Byte;
    {-Return sequence number of oldest possible sequence number}
    {-Current Seq - (kTableSize)}
  begin
    with P^ do begin
      {Handle case of no windows}
      if kTableSize = 1 then begin
        kpLoSeq := kRecBlockNum;
        Exit;
      end;

      kpLoSeq := kInfoTable[kTableTail].Seq;
    end;
  end;

  function kpHiSeq(P : PProtocolData) : Byte;
    {-Return sequence number of highest acceptable sequence number}
  var
    I     : Byte;
    Count : Byte;
  begin
    with P^ do begin
      {Handle case of no windows}
      if kTableSize = 1 then begin
        kpHiSeq := kRecBlockNum;
        Exit;
      end;

      {Search backwards counting free (acked) slots}
      I := kpPrevSeq(P, kTableHead);
      Count := 0;
      repeat
        with kInfoTable[I] do
          if Acked or not InUse then
            Inc(Count);
        I := kpPrevSeq(P, I);
      until (I = kTableHead);

      {HiSeq is current sequence number + Count}
      Inc(Count, kRecBlockNum);
      if Count > 64 then
        Dec(Count, 64);
      kpHiSeq := Count;
    end;
  end;

  function kpSeqDiff(P : PProtocolData; Seq1, Seq2 : Byte) : Byte;
    {-Assuming Seq1 > Seq2, return the difference}
  begin
    with P^ do begin
      if Seq1 > Seq2 then
        kpSeqDiff := Seq1-Seq2
      else
        kpSeqDiff := (Seq1+64)-Seq2;
    end;
  end;

  procedure kpAddToTable(P : PProtocolData; Seq : Byte);
    {-Add Seq to proper location in table}
  var
    CurSeq : Byte;
    HeadSeq : Byte;
    I : Cardinal;
    Diff : Cardinal;
  begin
    with P^ do begin
      {Calculate kTableHead value for Seq (range known to be OK)}
      HeadSeq := kInfoTable[kTableHead].Seq;

      if kpSeqGreater(P, Seq, HeadSeq) then begin
        {Incoming packet is new, rotate table, writing old slots as required}
        Diff := kpSeqDiff(P, Seq, HeadSeq);
        for I := 1 to Diff do begin
          kTableHead := kpNextSeq(P, kTableHead);
          if kTableHead = kTableTail then begin
            if kInfoTable[kTableTail].InUse then begin
              kpWritePacket(P, kTableTail);
              kInfoTable[kTableTail].InUse := False;
              kInfoTable[kTableTail].Acked := False;
            end;
            kTableTail := kpNextSeq(P, kTableTail);
          end;
        end;
        I := kTableHead;

      end else begin
        {Incoming packet is a retransmitted packet, find associated table index}
        CurSeq := HeadSeq;
        I := kTableHead;
        while CurSeq <> Seq do begin
          CurSeq := Dec64(CurSeq);
          I := kpPrevSeq(P, I);
        end;
      end;

      {Stuff info table}
      kInfoTable[I].Seq   := Seq;
      kInfoTable[I].Acked := True;
      kInfoTable[I].Len   := kRecDataLen;
      kInfoTable[I].InUse := True;

      {Stuff data table}
      Move(aDataBlock^, kDataTable^[(I-1)*aBlockLen], kRecDataLen);
    end;
  end;

  procedure kpSendNak(P : PProtocolData);
    {-Send an nak packet for packet Seq}
  const
    NakLen = 3;
  begin
    with P^ do begin
      kpPutHeader(P, KNak, NakLen);

      {Put checksum}
      kpSendBlockCheck(P);

      {Put terminator}
      kpSendTerminator(P);
    end;
  end;

  procedure kpSendAck(P : PProtocolData; Seq : Byte);
    {-Send an acknowledge packet for packet Seq}
  const
    AckLen : array[1..3] of Byte = (3, 4, 5);
  var
    B : Byte;
    Save : Byte;
  begin
    with P^ do begin
      B := AckLen[Byte(kKermitOptions.Check)-$30];

      {kpPutHeader uses aBlockNum so we'll need to change it temporarily}
      Save := aBlockNum;
      aBlockNum := Seq;

      kpPutHeader(P, KAck, B);

      {Put checksum}
      kpSendBlockCheck(P);

      {Put terminator}
      kpSendTerminator(P);

      aBlockNum := Save;
    end;
  end;

  function kpDataCount(P : PProtocolData; Index : Byte) : Cardinal;
    {-Count actual data characters in slot Index}
  var
    TIndex : Cardinal;
    DIndex : Cardinal;
    LastIndex : Cardinal;
    RepeatCnt : Cardinal;
    C : Char;
  begin
    with P^ do begin
      {Set starting indexes}
      TIndex := Cardinal(Index-1)*aBlockLen;                           
      LastIndex := Integer(TIndex)+kInfoTable[Index].Len;            
      DIndex := 1;

      {Loop through this block in kDataTable...}
      repeat
        {Get a character with escaping already translated}
        kpGetDataChar(P, C, TIndex, RepeatCnt);
        Inc(DIndex, RepeatCnt);
      until (TIndex = LastIndex);

      {Commit last, or only, block}
      kpDataCount := DIndex-1;
    end;
  end;

  procedure kpProcessDataPacket(P : PProtocolData);
    {-Process received data packet}
  var
    I : Cardinal;
    Count : Cardinal;
  begin
    with P^ do begin
      aProtocolError := ecOK;

      if (kpSeqGreater(P, kRecBlockNum, kpLoSeq(P)) or (kRecBlockNum = kpLoSeq(P))) and
         (kpSeqGreater(P, kpHiSeq(P), kRecBlockNum) or (kRecBlockNum = kpHiSeq(P))) then begin

        {Acceptable data packet}
        kpAddToTable(P, kRecBlockNum);

        {Exit on errors, will be handled by state machine}
        if aProtocolError <> ecOK then
          Exit;

        {Nak missing packets}
        if kpSeqGreater(P, kRecBlockNum, aBlockNum) then begin
          I := aBlockNum;
          repeat
            kpSendNak(P);
            I := Inc64(I);
          until I = kRecBlockNum;
        end else if kRecBlockNum = aBlockNum then begin
          {Adjust status variables}
          Count := kpDataCount(P, kTableHead);
          Inc(aBytesTransferred, Count);
          Dec(aBytesRemaining, Count);
          aElapsedTicks := ElapsedTime(aTimer);
        end;

        {Ack the packet we got}
        kpSendAck(P, kRecBlockNum);

        {Expect next highest sequence beyond highest table entry}
        aBlockNum := Inc64(kInfoTable[kTableHead].Seq);

      end else begin
        {Unacceptable block number, ignore it}
        aBlockNum := aBlockNum;
      end;
    end;
  end;

  function kpIncTableIndex(P : PProtocolData; Index, Increment : Byte) : Byte;
    {-Increment table index, wrap at table size}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -