[Back to STRINGS SWAG index] [Back to Main SWAG index] [Original]

    Unit USPat; {String pattern a-la Messy-DOS}
    { (C) 1994 William Arthur Barath.   Permission granted for free use in
      Commercial and Non-Commercial software. }

    { written oct 17/94 for TOMMY by WSEM at the request of Weird Al}
    { For use in UFO's text/file scanner.  Fast enough? }

    Interface

    Type pString = ^String;
    Var SpatStr:pString;

    Procedure UpCaseStr(Var s:String);
    {call to convert a VAR ARG string to upper case.  Don't use w/ PCHAR!}
    Procedure SetSPat(Var s:String);
    {call to set the pattern to test against with each following call to
     Spat.  This sets a global pointer to the given string and converts that
     string to a format that can be read optimally fast, which saves passing
     the pattern arguement to the SPat PROC via the stack, which saves many
     many clock cycles and memory R\W accesses. 'S' *must* be a string of at
     least 12 characters, or a typecast region of memory of at least 13 bytes
     formatted as a Pascal-style STRING or ugly things may happen.}
    Function SPat(Var s:String):Boolean;
    {tests the given VAR ARG string against the string pattern pointed to by
     the Public SpatStr global pointer.  Passing a VAR ARG takes much less
     time since only a 4-byte pointer is pushed onto the stack prior to calling
     this PROC, as opposed to a full STRING, which may be 256 bytes and would
    be
     pushed a single char at a time... yawn...}
    Function UCSPat(Var s:String):Boolean;
    {tests the given VAR ARG string against the string pattern pointed to by
     the Public SpatStr global pointer.  Passing a VAR ARG takes much less
     time since only a 4-byte pointer is pushed onto the stack prior to calling
     this PROC, as opposed to a full STRING, which may be 256 bytes and would
    be
     pushed a single char at a time... yawn... Works with UPCASE'd data}

    Implementation

    Procedure UpCaseStr(Var s:String);assembler;
    {up to 15 times faster than Borland's ASM demo code}
    asm Push ds;Lds si,s;Xor ch,ch;Lodsb;Mov cl,al;Jcxz @Done;Mov dx,'az';
    Mov ah,'a'-'A';Mov bx,-1;@Loop: Lodsb;Cmp al,dh;Jb @Upper;Cmp al,dl;
    ja @Upper;Sub al,ah;Mov [si+bx],al;@Upper: Loop @Loop;@Done: Pop ds;end;

    Procedure SetSPat(Var s:String);
    {I'd write this in ASM as well, but it isn't likely to enter a loop so
     speed isn't really critical, and it may be useful to edit this to alter
     the personality of the pattern matching algorhythm.}
    Type str12 = String[12];
    Var l,p:Word;pat:Str12;
    Begin
      If s[0]=#0 then s:='*.*';
       UpCaseStr(s);p:=1;
       For l:=1 to 12 do Case s[p] of
         '*':If l=9 then Begin Dec(l);Inc(p);end else pat[l]:='?';
         '.':If l=9 then Begin pat[l]:='.';Inc (p);end else pat[l]:=' ';
         Else Begin pat[l]:=s[p];If Char(p)<s[0] then Inc(p);end;
       end;
      Pat[0]:=Char(l);
      s:=pat;SPatStr:=@s;
    end;

    Function SPat(Var s:String):Boolean;assembler;
    asm
      Push ds           {do this or die... :-) }
        Lds si,SpatStr  {location of the pattern string}
        Les di,s        {location of the test string}
        Lodsb
        Mov cl,es:[di]  {length of the test string}
        xor ch,ch
        Jcxz @BadMatch  {if the test string is NULL then never match}
        Inc di
    @Search:
        Mov ah,es:[di]
        Cmp ah,'a'
        Jb  @Search2
        Cmp ah,'z'
        Ja  @Search2
        Sub ah,'a'-'A'  {convert the test string char to CAPS}
    @Search2:
        Lodsb           {read and advance a char in pattern}
        Cmp ah,al
        Jz  @Match2     {if the characters are = }
        Cmp al,'?'
        Jnz @BadMatch   {pattern didn't match}
    @Match:
        Cmp ah,'.'      {if '?' tries to match a dot, we try the next}
        jz  @search2    {char, which should be either '.' or '?'}
    @Match2:
        Inc di          {advance to the next test string char}
        Loop @Search    {test for # of chars in test string}
        Mov al,True
        Jnz @Done       {return 'True'}
    @BadMatch:
        xor ax,ax       {return 'False'}
    @Done:
      Pop ds            {do this or die... :-) }
    end;
    Function UCSPat(Var s:String):Boolean;assembler;
    asm
      Push ds           {do this or die... :-) }
        Lds si,SpatStr  {location of the pattern string}
        Les di,s        {location of the test string}
        Mov cl,[di]     {length of the test string}
        xor ch,ch
        Jcxz @Bad       {if the test string is NULL then never match}
        Inc cx          {use length+1, so when we hit 0 we know we're done}
        CMPSB           {sneaky way to INC DI and INC SI with one byte :-) }
        Mov dx,'?.'
        Mov bx,-1       {offset to last character.  faster than using immed.
    data}
    @Search:
        REPZ CMPSB      {compare bytes until one doesn't match or CX = 0}
        Jcxz @Good      {when we hit 0, we're done.  Last comparison was
    garbage}
        cmp dh,[si+bx]  {If last pattern byte <> '?' then match is bad}
        Jnz @Bad
        cmp dl,[di+bx]  {If last test byte <> '.' then check next chars}
        Jnz @Search
        Dec di          {otherwise, make sure remaining pattern chars}
        Inc cx          {are '?'.  Otherwise, pattern should fail}
        Jmp @Search
    @Good:
        Inc ch          {change the exit condition in ch from 0 to 1}
    @Bad:
        Mov al,ch
      Pop ds            {do this or die... :-) }
    end;
    end.

[Back to STRINGS SWAG index] [Back to Main SWAG index] [Original]