
 ; ------------------------------------------------------------------
 ;
 ; Function InPosT(sStr As String, sFind As String, _
 ;                 Optional ByVal lStartPos As Long = 1, _
 ;                 Optional ByVal lRightLimit As Long = 0) As Long
 ;
 ; InPosT searches for a substring in a unicode string in text compare
 ; mode, and if found returns the position of the first match as the
 ; function result.
 ;
 ; It uses a one based character index (1st character is 1, 2nd is 2 etc)
 ; for both the lStartPos parameter and the returned character position.
 ;
 ; If the optional start position is less than one it defaults to one.
 ;
 ; The optional right limit specifies the one based position in the
 ; string of the last possible pattern match. If omitted/less than one
 ; the string is searched from start pos to string end. This parameter
 ; specifies the limit of matching the last search pattern character.
 ;
 ; If the right limit parameter is beyond the length of the string
 ; the string is searched from start pos to string end.
 ; ------------------------------------------------------------------
 ; If the function succeeds, it returns the one based character index
 ; of the start of the first substring match, or:
 ;  0 = no match found
 ;  0 = substring longer than main string
 ;  0 = startpos out of range (startpos > len str - len substr)
 ;  0 = rightlimit out of range (0 < rightlimit < len substr)
 ; ------------------------------------------------------------------
 ; This procedure requires a module level integer array to be
 ; initialized by calling the UnsBuildTextCompTable sub-routine.
 ;
 ; Private lpTxtCmp As Long
 ; lpTxtCmp = UnsBuildTextCompTable ' Class Init before patch
 ; ------------------------------------------------------------------

 .486             ; 32-bit instruction set
 .model flat      ; Protected memory, 4GB limit
 .code            ; Start of code

InPosT proc near  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

   push ebp          ; preserve base pointer value
   mov ebp, esp      ; set up pointer to parameters
   sub esp, 8        ; offset stack pointer past vars

   string equ [ebp+12]
   find   equ [ebp+16]
   start  equ [ebp+20] ; friendly param names
   limit  equ [ebp+24]
   return equ [ebp+28]

   lpcase equ [ebp-4]  ; set up stack variables
   cntr   equ [ebp-8]

   pvData equ [ebx+12] ; safearray pointers
   cElems equ [ebx+16]

   push esi
   push edi            ; preserve registers
   push ebx

   align 4
   mov ebx, 2876543h ; txtcmp SA patched on init
   xor eax, eax      ; zero default return value
   test ebx,ebx      ; test header for zero ptr
   jz _exitp         ; exit if null SA pointer

   mov ecx, cElems   ; get cnt of lookup elements
   mov edi, pvData   ; get first lookup address
   cmp ecx, 10000h   ; check if count is valid
   jne _exitp        ; exit if not correctly init
   mov lpcase,edi    ; save ptr to first lookup

   mov esi, string   ; copy str descriptor
   mov edi, find     ; copy find descriptor
   mov esi,[esi]     ; extract str pointer
   mov edi,[edi]     ; extract find pointer

   test esi, esi     ; validate str pointer
   jz _exitp         ; exit null str pointer
   test edi, edi     ; validate find pointer
   jz _exitp         ; exit null find pointer

   mov ecx,[esi-4]   ; extract str byte length
   mov ebx,[edi-4]   ; extract find byte length
   mov edx, limit    ; copy right limit parameter

   test ecx, ecx     ; validate string length
   jz _exitp         ; exit empty string passed
   test ebx, ebx     ; validate pattern length
   jz _exitp         ; exit empty string passed

   shl edx, 1        ; convert opt param to bytes
   jbe _limit        ; opt param less than one (jcz)
   cmp edx, ecx      ; validate optional limit param
   jae _limit        ; limit range to string length
   mov ecx, edx      ; set search limit string pos
  _limit:            ; default search entire string

   mov edx, start    ; copy start position parameter
   sub ecx, ebx      ; calc last pos find can occur
   js _exitp         ; exit if str shorter than find

   dec edx           ; convert start pos to zero base
   jz _start         ; default start first character
   jns _tobytes      ; start pos greater than zero
   mov edx, eax      ; default first char 0 offset
   jmp _start        ; default start first character

  _tobytes:
   shl edx, 1        ; convert search start to bytes
   sub ecx, edx      ; is start pos within str len
   js _exitp         ; hit cannot occur after ecx

  _start:
   mov start,esi     ; cache string base address
   shr ecx, 1        ; convert counter to chars
   add esi, edx      ; set search start address
   inc ecx           ; offset cntr before start
   mov edx, eax      ; clear edx for wchar holder
   mov ebx,lpcase    ; get pointer to first lookup
   mov dx,[edi]      ; prep dx for 1st char search
   sub esi, 2        ; offset str ptr before start
   mov dx,[ebx+edx*2]; get lookup wchar from table

  _chr:              ; walk up str unicode chars
   add esi, 2        ; increment ptr to next wchar
   dec ecx           ; reduce counter by 1 wchar
   js _nomatch       ; reached search scope limit
   mov ax,[esi]      ; get current str char into ax
   cmp dx,[ebx+eax*2]; compare lookup with first find
   jne _chr          ; continue search for 1st char

   mov cntr,ecx      ; preserve counter value
   xor ecx, ecx      ; zero ecx char offset

  _nextchr:          ; compare the rest of pattern
   add ecx, 2        ; offset to next wchars
   mov dx,[edi+ecx]  ; assign next find char
   test dx, dx       ; test for null terminator
   jz _match         ; reached the end of find
   mov dx,[ebx+edx*2]; assign lookup wchar to dx
   mov ax,[esi+ecx]  ; get current str char into ax
   cmp dx,[ebx+eax*2]; compare lookup with find lookup
   je _nextchr       ; if match continue compare

   mov dx,[edi]      ; prep dx again 1st find char
   mov ecx,cntr      ; retrieve counter value
   mov dx,[ebx+edx*2]; get lookup wchar from table
   jmp _chr          ; continue with search

  _nomatch:
   xor eax, eax      ; set zero result
   jmp _exitp

  _match:
   sub esi, start    ; subtract string base addr
   mov eax, esi      ; assign hit position to eax
   shr eax, 1        ; convert result to char cnt
   inc eax           ; convert result to one base

  _exitp:
   mov edi, return   ; get address of return value
   mov [edi],eax     ; store the function result

   pop ebx
   pop edi           ; restore registers
   pop esi
   mov esp, ebp      ; reset stack pointer var offset
   pop ebp           ; restore base pointer register

   xor eax, eax      ; clear eax to tell VB all is okay
   ret 24            ; cleanup (lpO, p1, p2, p3, p4, rc)

 ; ------------------------------------------------------------------

InPosT endp     ; end of procedure
end InPosT      ; end of code, indicate entry point

 ; ------------------------------------------------------------------
