News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Find last index of

Started by DerCoder, March 24, 2012, 11:57:44 AM

Previous topic - Next topic

DerCoder

Good morning,

I want to find the last index of a single char in a string.
I have for example this string
Hello.dear.user
and when I call my function/method it returns my (by searching for the last '.') 10.

Thanks for reading ^^

dedndave

i would begin with a call to StrLen, which gets you the string length
then, starting at the end of the string and working backwards, find the first instance of the specified char

what would you want returned if the char isn't in the string ?
(-1 would probably be convenient   :P )

dedndave

;place this line near the beginning of the file
LastChar PROTO :LPSTR,:DWORD

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

LastChar PROC uses esi lpString:LPSTR,dwChar:DWORD

        mov     esi,lpString
        INVOKE  StrLen,esi
        add     esi,eax
        mov     ecx,eax
        mov     edx,dwChar

LastC0: sub     eax,1
        dec     esi
        jc      LastC1

        cmp     dl,[esi]
        jnz     LastC0

LastC1: ret

LastChar ENDP

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

dwChar is a byte (char), passed as a dword
the result is returned in EAX and is -1 if the char isn't in the string
also, ECX returns the string length and EDX returns the char   :P

you could use [ESI+EAX], but i don't think it'll be as fast

qWord

an other variation, which is also Unicode aware :bg
mov eax,-1
xor ecx,ecx
mov edx,chr$("hello.dear.user")
.while TCHAR ptr [edx+ecx*SIZEOF TCHAR]
cmp TCHAR ptr [edx+ecx*SIZEOF TCHAR],'.'
cmove eax,ecx
inc ecx
.endw

.if SDWORD ptr eax >= 0
; eax = index
.else
; no dot found
.endif
FPU in a trice: SmplMath
It's that simple!

DerCoder

@dedndave Can you explain me your code a bit? What's this
add esi, eax I am very new to asm and can't "read" it that good :D
Maybe you could put some comments? :)

@qWord Why do you use mov eax, -1 and why not xor eax, eax
dec eax


Thanks, DerCoder

qWord

Quote from: DerCoder on March 24, 2012, 12:58:51 PM@qWord Why do you use mov eax, -1 and why not xor eax, eax
dec eax

because there is no reason to calculate a contant - introductions size isn't importend in this case.
FPU in a trice: SmplMath
It's that simple!

dedndave

in the code i posted...
we get the address of the string in ESI
then, we call the StrLen function - that returns the length of the string in EAX
ESI is preserved across the call, so is unaltered
after that, we ADD ESI,EAX - now ESI points to the NULL terminator at the end of the string
then, we work backwards until:
a) the SUB EAX,1 generates a carry (EAX will be -1)
or
b) the character is found

qWords code is nice, but it uses a fixed char
and INC ECX may not work right 

qWord

FPU in a trice: SmplMath
It's that simple!

dedndave

shouldn't it be ADD ECX,sizeof TCHAR ???

dedndave

sorry - my mistake   :bg
cmp TCHAR ptr [edx+ecx*SIZEOF TCHAR],'.'

i didn't see the '*'   :P

DerCoder

Okay thank you twos. Your code helps me alot!

Now, how can i read the last words from the delemiter until the end?
So call LastChar, StrA$("hello.dear.user"), delemiter would return "user".

dedndave

what do you want to do with it ?
i know that may sound like a stupid question - lol

but - you have the index of the delimiter
add one to that, and you have the index of the last word
add that to the offset of the string, and you have the last word, already terminated with a 0

now, if you want to print it, simply use that address
it will not affect the rest of the string
if you want to copy it into some other buffer, that's a different story   :P

by the way, the correct use of a prototyped function is...
        INVOKE  LastChar, StrA$("hello.dear.user"), delemiter
the assembler generates code that looks something like this
        push    delemiter     ;misspelled, by the way  ;)
        push    offset string ;'hello.dear.user'
        call    LastChar

the CALL instruction does not allow parameters on the line

one problem you have is that you lose the offset of the temporary string
try this code...
        mov     eax,chr$("hello.dear.user")
        push    eax
        INVOKE  LastChar, eax, 46    ; period = 46
        pop     edx
        add     edx,eax
        inc     edx
        print   edx

dedndave

the original code posted above returns the delimiter in EDX
we can modify the routine so that it returns the offset of the original string in EDX, instead   :U

;place this line near the beginning of the file
LastChar PROTO :LPSTR,:DWORD

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

LastChar PROC uses esi lpString:LPSTR,dwChar:DWORD

        mov     esi,lpString
        INVOKE  StrLen,esi
        push    esi
        mov     ecx,eax
        add     esi,eax
        mov     edx,dwChar

LastC0: sub     eax,1
        dec     esi
        jc      LastC1

        cmp     dl,[esi]
        jnz     LastC0

LastC1: pop     edx
        ret

LastChar ENDP

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


with the modified routine, you might be able to do something like this...
        INVOKE  LastChar, chr$("hello.dear.user"), 46    ; period = 46
        add     edx,eax
        inc     edx
        print   edx

jj2007

Simple and straightforward:
include \masm32\include\masm32rt.inc

.code
LastChar proc uses esi pStr, delchar
  mov esi, pStr
  mov edx, delchar
  xor ecx, ecx
  .Repeat
lodsb
.if al==dl
mov ecx, esi ; delimiter found, remember position
.endif
  .Until !al ; end of string
  xchg eax, ecx ; return it in eax
  ret
LastChar endp

start: print "[" ; output should be [user]
invoke LastChar, chr$("hello.dear.user"), "."
.if eax
print eax, "]", 13, 10
.else
print "none] found", 13, 10
.endif
exit
end start

dedndave

here is a working example, as well...