;-------------------------------------------------------------------------------
;
; bstrInString procedure 
;
; Copyright (c) 2/28/01  Ernest Murphy
;
; For educational use only. Any commercial re-use only by written license
;
; useage prototype:
;
;    invoke bstrLeft, bstrSource, dwCCount, ADDR bstrReturn
;
; Description: extracts the first dwCCount characters from bstrSource, 
;   and returns it in *bstrName
;
;-------------------------------------------------------------------------------
.NOLIST
.386
.model flat, stdcall
option casemap:none ; case sensitive
;-------------------------------------------------------------------------------

include     bstrLib.inc
include     \masm32\include\oleaut32.inc

;-------------------------------------------------------------------------------
.LISTALL
.code
;-------------------------------------------------------------------------------
bstrInString PROC PUBLIC dwStartPos:DWORD, bstrString:DWORD, bstrSubStr:DWORD
  ; InString searches for a substring in a larger string and if it is
  ; found, it returns its position in eax. 
  ;
  ; It uses a one (1) based character index (1st character is 1,
  ; 2nd is 2 etc...) for both the "dwStartPos" parameter and the returned
  ; character position.
  ; Return Values.
  ; If succeeds, it returns the 1 based index of the start of the substring.
  ; If fails or no match found  0
  ; ------------------------------------------------------------------
    LOCAL cString :DWORD,     cSubStr :DWORD
    LOCAL pStringStart:DWORD, pStringStop:DWORD
    LOCAL pSubStrStart:DWORD, pSubStrStop:DWORD
	LOCAL oldecx:DWORD

	.IF (bstrString == NULL) || (bstrSubStr == NULL) || (dwStartPos == NULL)
		xor eax, eax				; zero = NOT FOUND
	.ENDIF

    dec dwStartPos                	; correct to 0 based index
    rol dwStartPos, 1				; convert chars to byte count of words
	mov eax, bstrString				; get ref to string
    mov pStringStart, eax			; and save
    mov pStringStop, eax			; get ready...
	mov eax, dwStartPos				; pStringStart  =  bstrString 
	add pStringStart, eax			;			     + 2*(dwStartPos-1)
    invoke SysStringByteLen, bstrString	; get string length
    mov cString, eax
    add pStringStop, eax			; pStringStop = bstrString + 

	mov eax, bstrSubStr				; get ref to SubStr
	mov pSubStrStart, eax			; and save
	mov pSubStrStop, eax			; get ready...
    invoke SysStringByteLen, bstrSubStr ; get string length
    mov cSubStr, eax
    add pSubStrStop, eax			; pStringStop = bstrSubStr + 

	; we can stop searchng the String cSubStr chars from end
	; (the trailng zero accounts for the lack of '-1'
	sub pStringStop, eax

	mov eax, cString
	.IF cSubStr > eax				; final check, will sub fit in string?
		xor eax, eax				; zero = NOT FOUND
		ret
	.ENDIF	
	mov ecx, pStringStart			; ecx ==> String
	mov edx, pSubStrStart			; edx ==> SubString
	.WHILE ecx <= pStringStop; loop to find 1st char of SubStr in String
		mov ax, [ecx]
		xor ax, [edx]
		.IF ZERO?					; we got a matching character!
			mov oldecx, ecx
			add edx, 2
			add ecx, 2
			.WHILE edx < pSubStrStop	; check if rest of SubStr follows
				xor eax, eax
				mov ax, [ecx]
				xor ax, [edx]
				.IF !ZERO?				; dang, not a match
					mov ecx, oldecx		; restore old pointers
					mov edx, pSubStrStart
					jmp OuterLoopEnd	; and re-start our char-by-char search	
				.ENDIF	
				add edx, 2				; still matching, inc both pointers
				add ecx, 2
			.ENDW						; and keep looking till end of SubStr
			; If we get here, we got a match
			mov eax, oldecx				; start addr of match in String
			sub eax, bstrString			;  - start addr of String = count
			; count is zero based, and in bytes not words
			ror eax, 1		; so divide by 2,
			inc eax			; then add 1, 
			ret				; then return it
		.ELSE
OuterLoopEnd: 				; no match here
			add ecx, 2		; point to next char in String
		.ENDIF
	.ENDW
	; oops, if we're here, no match at all
	xor eax, eax			; zero = NOT FOUND
	ret
;Get_Outa_Here:
    ret
bstrInString endp
;-------------------------------------------------------------------------------

END