Valhalla Legends Forums Archive | Assembly Language (any cpu) | SStrChr and SStrChrR - annotated

AuthorMessageTime
iago
Just for fun, here's a couple of simple storm functions:

[code].text:1503AA50 ; Returns the substring after the first occurance of the specific character in the string. Returns NULL if the character is not found.
.text:1503AA50
.text:1503AA50 ; char *__fastcall SStrChr(char *str,char c)
.text:1503AA50 public SStrChr
.text:1503AA50 SStrChr proc near ; CODE XREF: SBmpSaveImageEx+6Dp
.text:1503AA50 ; SBmpSaveImageEx+7Ap ...
.text:1503AA50 mov eax, ecx ; Move the string into eax
.text:1503AA52 test eax, eax ; Ensure that it's a valid character
.text:1503AA54 jnz short SStrChrValidString
.text:1503AA56 push ERROR_INVALID_PARAMETER ; dwErrCode
.text:1503AA58 call SErrSetLastError
.text:1503AA5D xor eax, eax
.text:1503AA5F retn
.text:1503AA60 ; ---------------------------------------------------------------------------
.text:1503AA60
.text:1503AA60 SStrChrValidString: ; CODE XREF: SStrChr+4j
.text:1503AA60 mov cl, [eax] ; Move the current character into ecx
.text:1503AA62 test cl, cl ; Check if it's null
.text:1503AA64 jz short SStrChrReturn0 ; If it's null, return 0
.text:1503AA66
.text:1503AA66 SStrChrTop: ; CODE XREF: SStrChr+20j
.text:1503AA66 cmp cl, dl ; Compare the current character to the character we're looking for
.text:1503AA68 jz short SStrChrReturn ; If they're equal, return the rest of the string
.text:1503AA6A mov cl, [eax+1] ; ecx gets the next character into the string
.text:1503AA6D inc eax ; eax goes to the next character
.text:1503AA6E test cl, cl ; Check if the character is null
.text:1503AA70 jnz short SStrChrTop
.text:1503AA72
.text:1503AA72 SStrChrReturn0: ; CODE XREF: SStrChr+14j
.text:1503AA72 xor eax, eax
.text:1503AA74
.text:1503AA74 SStrChrReturn: ; CODE XREF: SStrChr+18j
.text:1503AA74 retn
.text:1503AA74 SStrChr endp
[/code]

[code]
.text:1503AA80 ; Exported entry 570.
.text:1503AA80 ; Exported entry 572.
.text:1503AA80
.text:1503AA80
.text:1503AA80 ; Returns the address of the final occurance of c within the string str. If it is not found, NULL is returned.
.text:1503AA80
.text:1503AA80 ; char *__fastcall SStrChrR(const char *str,char c)
.text:1503AA80 public SStrChrR
.text:1503AA80 SStrChrR proc near ; CODE XREF: sub_15001420+82p
.text:1503AA80 ; sub_150024C0+D3p ...
.text:1503AA80 test ecx, ecx ; Make sure we have a non-null string
.text:1503AA82 jnz short SStrChrValidParameter
.text:1503AA84 push ERROR_INVALID_PARAMETER ; dwErrCode
.text:1503AA86 call SErrSetLastError
.text:1503AA8B xor eax, eax ; return 0
.text:1503AA8D retn
.text:1503AA8E ; ---------------------------------------------------------------------------
.text:1503AA8E
.text:1503AA8E SStrChrValidParameter: ; CODE XREF: SStrChrR+2j
.text:1503AA8E push ebx
.text:1503AA8F mov bl, [ecx] ; Move the first character in ecx to bl
.text:1503AA91 push esi
.text:1503AA92 xor esi, esi ; Clear esi
.text:1503AA94 test bl, bl ; Check if the character is null
.text:1503AA96 jz short SStrChrReturnEsi
.text:1503AA98
.text:1503AA98 SStrChrTopLoop: ; CODE XREF: SStrChrR+24j
.text:1503AA98 cmp bl, dl ; Compare the character to the character we're searching for
.text:1503AA9A jnz short SStrChrNotEqual
.text:1503AA9C mov esi, ecx ; If they're equal, move the character here
.text:1503AA9E
.text:1503AA9E SStrChrNotEqual: ; CODE XREF: SStrChrR+1Aj
.text:1503AA9E mov bl, [ecx+1] ; Set the current character to the next character
.text:1503AAA1 inc ecx ; Go to the next character
.text:1503AAA2 test bl, bl ; Loop as long as we aren't at null
.text:1503AAA4 jnz short SStrChrTopLoop ; Compare the character to the character we're searching for
.text:1503AAA6
.text:1503AAA6 SStrChrReturnEsi: ; CODE XREF: SStrChrR+16j
.text:1503AAA6 mov eax, esi
.text:1503AAA8 pop esi
.text:1503AAA9 pop ebx
.text:1503AAAA retn
.text:1503AAAA SStrChrR endp
[/code]

One question I have is, why do they each have 2 ords? Is there some reason for that?
May 15, 2004, 1:36 AM
Eibro
I don't have a lot of experience doing this, but here's my go at converting it to C
[code]char* __fastcall SStrChrR( const char* str, char c ) {

   if ( str == NULL ) {
      SSetLastError( ERROR_INVALID_PARAMETER );
      return NULL;
   }

   char* found = NULL;
   while ( *str != NULL ) {
      if ( c == *str )
         found = str;
   }

   return found;
}

char* __fastcall SStrChr( char* str, char c ) {

   if ( str == NULL ) {
      SSetLastError( ERROR_INVALID_PARAMETER );
      return NULL;
   }
   
   while ( *str != c || *str != NULL ) ++str;

   return str;
}[/code]
May 15, 2004, 4:28 AM
iago
I believe your while loop in the SStrChr should be &&, not ||
May 15, 2004, 8:20 AM
Moonshine
[quote author=Eibro[yL] link=board=7;threadid=6808;start=0#msg60202 date=1084595309]
I don't have a lot of experience doing this, but here's my go at converting it to C
[code]char* __fastcall SStrChrR( const char* str, char c ) {

if ( str == NULL ) {
SSetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}

char* found = NULL;
while ( *str != NULL ) {
if ( c == *str )
found = str;
}

return found;
}

char* __fastcall SStrChr( char* str, char c ) {

if ( str == NULL ) {
SSetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}

while ( *str != c || *str != NULL ) ++str;

return str;
}[/code]
[/quote]

You missed the char* incrementation in your first function.

Here's what I got:

[code]
char * __fastcall SStrChr( char * str, char ch ) {
if (!str) {
//SErrSetLastError(ERROR_INVALID_PARAMETER);
return (NULL);
}

for (int i = 0; *str; i++, *str++)
if (*str == ch)
return (str);

return (NULL);
}

const char * __fastcall SStrChrR( const char * str, char ch ) {
   if (!str) {
      //SErrSetLastError(ERROR_INVALID_PARAMETER);
      return (NULL);
   }

   int i;
   const char * pRet = NULL;
   for (i = 0; *str; i++, *str++)
      if (*str == ch)
         pRet = str;

   return (pRet);
}
[/code]


Edit: Iago, are you SURE the second function isn't returning a const char*? It doesn't really make sense otherwise.

May 15, 2004, 9:13 PM
Adron
I don't see why a strchr function should return a const char* instead of a char*. Makes much more sense to return a char*.

The found variable going out of scope is not a problem.

May 15, 2004, 9:20 PM
Moonshine
I forgot that found was pointing to the parameter itself -- my bad. Anyways, SStrChrR should definitely be returning a const char * if the parameter is const char *. Otherwise, you'd need to const_cast<>() it at return, and that's dangerous.
May 15, 2004, 9:32 PM
Adron
[quote author=Moonshine link=board=7;threadid=6808;start=0#msg60284 date=1084656762]
I forgot that found was pointing to the parameter itself -- my bad. Anyways, SStrChrR should definitely be returning a const char * if the parameter is const char *. Otherwise, you'd need to const_cast<>() it at return, and that's dangerous.
[/quote]

Ah. I got confused because you said the second function, and in the C++ post, it's the argument of the first function that is const char *. Either way; I think he put a const on it that shouldn't be there. It's very useful to have strchr and strrchr return a char *.
May 15, 2004, 10:09 PM
Maddox
[quote author=Moonshine link=board=7;threadid=6808;start=0#msg60274 date=1084655629]
You missed the char* incrementation in your first function.

Here's what I got:

[code]
char * __fastcall SStrChr( char * str, char ch ) {
if (!str) {
//SErrSetLastError(ERROR_INVALID_PARAMETER);
return (NULL);
}

for (int i = 0; *str; i++, *str++)
if (*str == ch)
return (str);

return (NULL);
}

const char * __fastcall SStrChrR( const char * str, char ch ) {
   if (!str) {
      //SErrSetLastError(ERROR_INVALID_PARAMETER);
      return (NULL);
   }

   int i;
   const char * pRet = NULL;
   for (i = 0; *str; i++, *str++)
      if (*str == ch)
         pRet = str;

   return (pRet);
}
[/code]


Edit: Iago, are you SURE the second function isn't returning a const char*? It doesn't really make sense otherwise.


[/quote]

More like
[code]
char * __fastcall SStrChr( char * str, char ch ) {
if (!str) {
//SErrSetLastError(ERROR_INVALID_PARAMETER);
return (NULL);
}

while(*str) {
if (*str == ch)
return (str);
str++;
}

return (NULL);
}
[/code]
May 15, 2004, 10:33 PM

Search