NSIS: StrContains function – Find the index of a sub string.

Recently I was out of internet and I needed to implement a function that would search if a String was part of another String for an NSIS installer.
Here’s my rendition of such a function. Once I came back online I found out about StrStr, but here’s another option that gives you as output the starting index on the bigger string (aka Haystack) if the smaller string (aka Needle) is found. Otherwise, it returns -1.

; ————————————————
; StrContains
; Returns starting index of where a string is contained inside another string (case sensitive)
; Usage: !insertmacro StrContains ${HayStack} ${Needle} ${Output}
; Parameters:
; HayStack – The string that could contain the substring you’re looking for
; Needle – The string you are looking for
; Output – -1 if the needle is not in the haystack, or the offset where it exists.

Var HaystackOffset ;current offset on haystack to copy NeedleLength characters into HayStackBuffer
Var HaystackLength ;size of the big string
Var MaxHaystackOffset ;maximum offset we can reach
Var NeedleLength ;length of string we’re looking for
Var HaystackBuffer ;substring we get on each iteration

!macro StrContains Haystack Needle Output
;we’ll be repeating this operation until we’ve reached
;HayStackLength – NeedleLength

;Get the lengths of the strings.
StrLen $HaystackLength ${Haystack}
StrLen $NeedleLength ${Needle}
StrCpy $HaystackOffset 0

;Determine what’s the maximum offset we can use to search for the substring
IntOp $MaxHaystackOffset $HaystackLength – $NeedleLength
IntOp $MaxHaystackOffset $MaxHaystackOffset – 1

;Make sure needle is not bigger than haystack
IntCmp $NeedleLength $HaystackLength LoopStart LoopStart DidNotFindIt

StrCpy $HaystackOffset -1
Goto Finish

;Start of substring comparison loop
;copy the substring to a buffer
StrCpy $HaystackBuffer ${Haystack} $NeedleLength $HaystackOffset

;It’s pretty cool if you uncomment this.
;MessageBox MB_ICONINFORMATION|MB_OK "[Loop] Buffer: [$HaystackBuffer] Offset: [$HaystackOffset]"

;If we’re done, we return the current haystackoffset
StrCmpS $HaystackBuffer ${Needle} Finish FigureOutNextStep

;Did we reach the end, or can we move a bit more

;Move offset 1 character to the right and see if we can keep going
IntOp $HaystackOffset $HaystackOffset + 1
IntCmp $HaystackOffset $MaxHaystackOffset LoopStart LoopStart DidNotFindIt

StrCpy ${Output} $HaystackOffset

Submit a comment