[Snippet] IfTextContains (function)

monday

Well-Known Member
Joined
Jun 23, 2014
Messages
922
Likes
4
Points
68
#1
Simple but useful function which can be used to check whether text contains some phrase:

Code:
//if call @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected]
:IfTextContains
{
    [email protected] - the main text
    [email protected] - piece of text to be found within the main text
}
 0C18: [email protected] = strstr string1 [email protected] string2 [email protected]
    if [email protected] > 1
    then
    0485:  return_true
    else
    059A:  return_false
    end
ret 0

Example:
The code below was tested with Cleo 4.1, Samp 0.3.7 and Sampfuncs 5.3.1

Code:
{$CLEO .cs}
0000: NOP

// wait to make sure the samp chat is there

repeat
wait 50
until 0AFA: is_samp_structures_available







// prepare the data

alloc [email protected] 100 // main text
format [email protected] "Important message received: It's ok to be white."

alloc [email protected] 100 // piece of text to check for
format [email protected] "message received"

alloc [email protected] 100 // piece of text that is deliberately different from the original 
format [email protected] "nussugu rucuuvud"






// use the actual function

if call @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected]
then
chatmsg "'message received' was found within the provided text" -1
end

if call @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected]
then
//nothing
else
chatmsg "'nussugu rucuuvud' was NOT found within the provided text" -1
end




// terminate this mod

end_thread



// the actual function which can be put anywhere at the end of the script (outside of any loops/labels/codeflow)
//if call @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected]
:IfTextContains
{
    [email protected] - the main text
    [email protected] - piece of text to be found within the main text
}
 0C18: [email protected] = strstr string1 [email protected] string2 [email protected]
    if [email protected] > 1
    then
    0485:  return_true
    else
    059A:  return_false
    end
ret 0
Edit:
P.S.
0C18 opcode doesn't return an index, it returns a pointer to the substring, so that's why there's ">1" check. If you'd like to know at which part of the main text the phrase was found you could substract [email protected] (phrase within text pointer) by the [email protected] (main text pointer). You could also return [email protected] from the function if you don't need the part of the text before given phrase.
Code:
if 0C18: [email protected] = strstr mainTextPointer [email protected] pieceToFindPointer [email protected]
then
chatmsg "Phrase was found within text. Pointer to it = %d" -1 [email protected]
end
Neccessary part of the code which has to be put somewhere at the end of the script (not inside any loop):
Code:
//if 0AB1: call_scm_func @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected] _returnedPointer [email protected]
:IfTextContains
{
    [email protected] - the main text
    [email protected] - piece of text to be found within the main text
} 
0AB1: @StrLen 1 strPtr [email protected] _length [email protected]
0AB1: @StrLen 1 strPtr [email protected] _length [email protected] 

//initial length check (the phrase can't be longer than the main text)
if 001D:   [email protected] > [email protected]  // (int)
then
059A:  return_false
0AB2: ret 1 0
end

[email protected] -= 1 
[email protected] = 0 // counter of the same chars in a row 
for [email protected] = 0 to [email protected] // for each char of the main text  ([email protected] = index)    
    0085: [email protected] = [email protected] // (int)
    005A: [email protected] += [email protected]  // (int)
    0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0
    
    0085: [email protected] = [email protected] // (int)
    005A: [email protected] += [email protected]  // (int)
    0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0

    if 003B:   [email protected] == [email protected]  // (int)   
    then
    [email protected]++
        if 002D:   [email protected] >= [email protected]  // (int)
        then
        0485:  return_true
        0062: [email protected] -= [email protected]  // (int)
        [email protected] += 1
        0AB2: ret 1 [email protected]
        end
    else
        if [email protected] > 0
        then
        [email protected] //check the same char again and assume it's the begining of the string but only if there was matching parts before (otherwise it would go back all the time and make infinite loop)
        end
    [email protected] = 0 
    end           
end 
 
059A:  return_false
0AB2: ret 1 0

//0AB1: @StrLen 1 strPtr [email protected] _length [email protected]
:StrLen
{
    [email protected] - string pointer
}
[email protected] = 0
for [email protected] = 0 to 100000
0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0
    if [email protected] == 0
    then
    break
    else
    [email protected]++
    [email protected]++
    end
end 
0AB2: ret 1 [email protected]
Usage:
Code:
if 0AB1: call_scm_func @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected] _returnedPointer [email protected]
then
//[email protected] is the pointer to the substring
end

Example of a full code:
Code:
{$CLEO .cs}
0000: NOP

wait 20000

{ 
    ----------------------
           PREPARATION
    ----------------------
}

0AC8: [email protected] = allocate_memory_size 100
0AC8: [email protected] = allocate_memory_size 100

0AD3: [email protected] = format "Important message"
0AD3: [email protected] = format "ant"


{ 
    ----------------------
           USAGE
    ----------------------
}

if 0AB1: call_scm_func @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected] _returnedPointer [email protected]
then
0AD1: show_formatted_text_highpriority "Text ~G~contains ~W~the phrase. Pointer: %d" time 2000 [email protected]
chatmsg [email protected] -1
wait 2000
else
0AD1: show_formatted_text_highpriority "Text ~R~doesn't contain ~w~the phrase" time 2000
wait 2000
end

0A93: end_custom_thread







{ 
    ----------------------
           FUNCTIONS 
    ----------------------
}

//if 0AB1: call_scm_func @IfTextContains 2 mainTextPointer [email protected] pieceToFindPointer [email protected] _returnedPointer [email protected]
:IfTextContains
{
    [email protected] - the main text
    [email protected] - piece of text to be found within the main text
} 
0AB1: @StrLen 1 strPtr [email protected] _length [email protected]
0AB1: @StrLen 1 strPtr [email protected] _length [email protected] 

//initial length check (the phrase can't be longer than the main text)
if 001D:   [email protected] > [email protected]  // (int)
then
059A:  return_false
0AB2: ret 1 0
end

[email protected] -= 1 
[email protected] = 0 // counter of the same chars in a row 
for [email protected] = 0 to [email protected] // for each char of the main text  ([email protected] = index)    
    0085: [email protected] = [email protected] // (int)
    005A: [email protected] += [email protected]  // (int)
    0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0
    
    0085: [email protected] = [email protected] // (int)
    005A: [email protected] += [email protected]  // (int)
    0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0

    if 003B:   [email protected] == [email protected]  // (int)   
    then
    [email protected]++
        if 002D:   [email protected] >= [email protected]  // (int)
        then
        0485:  return_true
        0062: [email protected] -= [email protected]  // (int)
        [email protected] += 1
        0AB2: ret 1 [email protected]
        end
    else
        if [email protected] > 0
        then
        [email protected] //check the same char again and assume it's the begining of the string but only if there was matching parts before (otherwise it would go back all the time and make infinite loop)
        end
    [email protected] = 0 
    end           
end 
 
059A:  return_false
0AB2: ret 1 0

//0AB1: @StrLen 1 strPtr [email protected] _length [email protected]
:StrLen
{
    [email protected] - string pointer
}
[email protected] = 0
for [email protected] = 0 to 100000
0A8D: [email protected] = read_memory [email protected] size 1 virtual_protect 0
    if [email protected] == 0
    then
    break
    else
    [email protected]++
    [email protected]++
    end
end 
0AB2: ret 1 [email protected]
 

springfield

Well-Known Member
Staff member
Joined
Feb 18, 2005
Messages
2,935
Likes
17
Points
88
Website
www.ugbase.eu
#3
RE: IfTextContains (function)

I'd rather follow this tutorial http://ugbase.eu/Thread-Tutorial-Using-functions-from-Windows-libraries
And wrap shlwapi.dll StrStr or StrStrI in a function, or roll your own, without any dependencies like SF.
 
OP
OP
monday

monday

Well-Known Member
Joined
Jun 23, 2014
Messages
922
Likes
4
Points
68
#4
RE: IfTextContains (function)

I think it's more because of some peculiar kind of shame rather than because someone will actually use it but I added the code aiming to make it work without sampfuncs

(tested it with sampfuncs though :p)
 
Top