home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / packer / arc / arctool / searches.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-29  |  6.8 KB  |  188 lines

  1. {                      F i l e    I n f o r m a t i o n
  2.  
  3. * DESCRIPTION
  4. A Turbo Pascal 4.0 unit for rapidly searching a buffer for a string.
  5. Version 1.0. Author Scott Bussinger.
  6.  
  7. * ASSOCIATED FILES
  8. SEARCHES.PAS
  9. BOYER.DOC
  10. SEARCHES.DOC
  11.  
  12. }
  13. {$R-,S+,I-,D-,T-,F-,V-,B-,N-}
  14.  
  15. unit Searches;
  16.  
  17. { A unit for rapidly searching a buffer for a string.
  18.  
  19.   Version 1.00 - 10/26/1987 - First general release
  20.  
  21.   Scott Bussinger
  22.   Professional Practice Systems
  23.   110 South 131st Street
  24.   Tacoma, WA  98444
  25.   (206)531-8944
  26.   Compuserve 72247,2671
  27.  
  28.   BlockPos was originally written by Randy Forgaard for use with Turbo
  29.   Pascal version 3.0.
  30.  
  31.   The Boyer-Moore routines were originally written by Van Hall for Turbo
  32.   Pascal version 3.0 and have been extensively rearranged for optimum use
  33.   with Turbo Pascal 4.0.  Note that the Boyer-Moore routines are MUCH, MUCH
  34.   slower than using BlockPos (which is written with inline code). }
  35.  
  36.  
  37. interface
  38.  
  39. function BlockPos(var Buffer;Size: word;S: string): integer;
  40.   { Search in Buffer of Size bytes for the string S }
  41.  
  42. type BoyerTable = record
  43.        Match: string;
  44.        MatchLength: byte;
  45.        Table: array[char] of byte
  46.        end;
  47.  
  48. procedure MakeBoyerTable(MatchString: string;var Table: BoyerTable);
  49.   { Generate the necessary table for doing a Boyer-Moore search }
  50.  
  51. function BoyerMoore(var BufferAddr;Size: word;Start: word;var Table: BoyerTable): word;
  52.   { Search a Buffer of Size characters beginning at Start for the match string defined in Table }
  53.  
  54.  
  55. implementation
  56.  
  57. function BlockPos(var Buffer;Size: word;S: string): integer;
  58.   { Search in Buffer of Size bytes for the string S }
  59.   begin
  60.   { Load "buffer" address into ES:DI, "buffer" offset into BX, Length(s) -
  61.     1 into DX, contents of "s[1]" into AL, offset of "s[2]" into SI, and
  62.     "size" - Length(s) + 1 into CX.  If "size" < Length(s), or if
  63.     Length(s) = 0, return zero. }
  64.  
  65.   Inline($1E/               {        PUSH    DS           }
  66.          $16/               {        PUSH    SS           }
  67.          $1F/               {        POP     DS           }
  68.          $C4/$BE/>buffer/   {        LES     DI,buffer[BP]}
  69.          $89/$FB/           {        MOV     BX,DI        }
  70.          $8B/$8E/>size/     {        MOV     CX,size[bp]  }
  71.          $8D/$B6/>s+2/      {        LEA     SI,s+2[bp]   }
  72.          $8A/$86/>s+1/      {        MOV     AL,s+1[bp]   }
  73.          $8A/$96/>s/        {        MOV     DL,s[bp]     }
  74.          $84/$D2/           {        TEST    DL,DL        }
  75.          $74/$23/           {        JZ      ERROR        }
  76.          $FE/$CA/           {        DEC     DL           }
  77.          $30/$F6/           {        XOR     DH,DH        }
  78.          $29/$D1/           {        SUB     CX,DX        }
  79.          $76/$1B/           {        JBE     ERROR        }
  80.  
  81.   { Scan the ES:DI buffer, looking for the first occurrence of "s[1]."  If
  82.     not found prior to reaching Length(s) characters before the end of the
  83.     buffer, return zero.  If Length(s) = 1, the entire string has been
  84.     found, so report success. }
  85.  
  86.        $FC/               {        CLD                  }
  87.        $F2/               {NEXT:   REPNE                }
  88.        $AE/               {        SCASB                }
  89.        $75/$16/           {        JNE     ERROR        }
  90.        $85/$D2/           {        TEST    DX,DX        }
  91.        $74/$0C/           {        JZ      FOUND        }
  92.  
  93.   { Compare "s" (which is at SS:SI) with the ES:DI buffer, in both cases
  94.     starting with the first byte just past the length byte of the string.
  95.     If "s" does not match what is at the DI position of the buffer, reset
  96.     the registers to the values they had just prior to the comparison, and
  97.     look again for the next occurrence of the length byte. }
  98.  
  99.          $51/               {        PUSH    CX           }
  100.          $57/               {        PUSH    DI           }
  101.          $56/               {        PUSH    SI           }
  102.          $89/$D1/           {        MOV     CX,DX        }
  103.          $F3/               {        REPE                 }
  104.          $A6/               {        CMPSB                }
  105.          $5E/               {        POP     SI           }
  106.          $5F/               {        POP     DI           }
  107.          $59/               {        POP     CX           }
  108.          $75/$EC/           {        JNE     NEXT         }
  109.  
  110.   { String found in buffer.  Set AX to the offset, within buffer, of the
  111.     first byte of the string (the length byte), assuming that the first
  112.     byte of the buffer is at offset 1. }
  113.  
  114.          $89/$F8/           {FOUND:  MOV     AX,DI        }
  115.          $29/$D8/           {        SUB     AX,BX        }
  116.          $EB/$02/           {        JMP     SHORT RETURN }
  117.  
  118.   { An "error" condition.  Return zero. }
  119.  
  120.          $31/$C0/           {ERROR:  XOR     AX,AX        }
  121.          $89/$46/$FE/       {RETURN: MOV     [BP-2],AX    }
  122.          $1F)               {        POP     DS           }
  123.   end;
  124.  
  125. procedure MakeBoyerTable(MatchString: string;var Table: BoyerTable);
  126.   { Generate the necessary table for doing a Boyer-Moore search }
  127.   var Counter: byte;
  128.   begin
  129.   with Table do
  130.     begin
  131.     Match := MatchString;
  132.     MatchLength := length(MatchString);
  133.     fillChar(Table,sizeof(Table),MatchLength);
  134.     if MatchLength > 0 then
  135.       for Counter := pred(MatchLength) downto 1 do
  136.         if Table[Match[Counter]] = MatchLength then
  137.             Table[Match[Counter]] := MatchLength-Counter
  138.     end
  139.   end;
  140.  
  141. function BoyerMoore(var BufferAddr;Size: word;Start: word;var Table: BoyerTable): word;
  142.   { Search a Buffer of Size characters beginning at Start for the match string defined in Table }
  143.   type Ptr = record
  144.          case integer of
  145.            0: (Ptr: ^char);
  146.            1: (Offset: word;
  147.                Segment: word)
  148.          end;
  149.   var Buffer: array[1..$FFF1] of char absolute BufferAddr;
  150.       BufferPtr: Ptr;
  151.       BufferEndOfs: word;
  152.       MatchPtr: Ptr;
  153.       MatchEndPtr: Ptr;
  154.   begin
  155.   with Table do
  156.     if MatchLength = 0                           { Are we looking for an empty string? }
  157.      then
  158.       BoyerMoore := 0
  159.      else
  160.       begin
  161.       MatchEndPtr.Ptr := @Match[MatchLength];
  162.       MatchPtr := MatchEndPtr;
  163.       BufferPtr.Ptr := @Buffer[pred(Start+MatchLength)];
  164.       BufferEndOfs := ofs(Buffer[Size]);
  165.       repeat
  166.         if BufferPtr.Ptr^ = MatchPtr.Ptr^
  167.          then
  168.           begin
  169.           dec(BufferPtr.Offset);
  170.           dec(MatchPtr.Offset)
  171.           end
  172.          else
  173.           begin
  174.           MatchPtr := MatchEndPtr;
  175.           inc(BufferPtr.Offset,Table[BufferPtr.Ptr^])
  176.           end
  177.       until (MatchPtr.Ptr=@Match) or (ofs(BufferPtr.Ptr^)>=BufferEndOfs);
  178.       if MatchPtr.Ptr = @Match
  179.        then
  180.         BoyerMoore := ofs(BufferPtr.Ptr^) - ofs(Buffer) + 2
  181.        else
  182.         BoyerMoore := 0
  183.       end
  184.   end;
  185.  
  186. end.
  187. 
  188.