Please help! This code is suppose to fill in the shorter of two strings w/ '0s'. For example if the user enters: '22222' and '2' the result is '22222' and '00002'.

For whatever reason if the any of the two strings is longer than 1 digit, while the other is also longer than 1 digit, it doesn't work right. If I enter for example, '22222' and '22' the result is '22222' and '0002_' instead of it being '22222' and '00022'.

Or if I enter for example, '222' and '33333' the result is '002__' and '33333' instead of it being '00222' and '33333'. I can't find the flaw in the algorithm.

Anyways, here's the code:




Prepare:
INVOKE Str_length, ADDR FPVal_W1
mov ecx, eax
INVOKE Str_length, ADDR FPVal_W2

cmp ecx, eax

ja Fill_Whole1 ; jump if (FPVal_W1 > FPVal_W2) to Fill_Whole1
jb Fill_Whole2 ; jump if (FPVal_W2 > FPVal_W1) to Fill_Whole2
jmp Addition1 ; jump if (FPVal_W1 == FPVwal_W2) to Addition1



Fill_Whole1:

; move the existing stuff
INVOKE Str_length, ADDR FPVal_W2
mov ecx, eax
INVOKE Str_length, ADDR FPVal_W1
sub eax, ecx
lea esi,
lea edi,
std
;mov byte ptr ,0
rep movsb
cld
; fill it with '0's
mov ecx, eax
lea edi,
mov al, '0'
rep stosb

;inc edi
;mov byte ptr , 0
jmp Print

Fill_Whole2:

; move the existing stuff
INVOKE Str_length, addr FPVal_W1
mov ecx, eax
INVOKE Str_length, addr FPVal_W2
sub eax, ecx
lea esi,
lea edi,
std
rep movsb
cld
; fill it with '0's
mov ecx, eax
lea edi,
mov al, '0'
rep stosb

inc edi
mov byte ptr , 0
jmp Print

Posted on 2003-04-22 19:21:33 by locke
Do you have any idea what values you are putting into your registers?
Fill_Whole1:


; move the existing stuff
INVOKE Str_length, ADDR FPVal_W2 ; I'm assuming length does not include 0 byte.
mov ecx, eax
INVOKE Str_length, ADDR FPVal_W1 ; [b]I'm assuming your proc preserves ECX[/b]
sub eax, ecx ; compute difference in size
lea esi, [ecx + FPVal_W2 - 1] ; set SOURCE addr to last digit of FPVal_W2
lea edi, [eax + FPVal_W2] ; set DEST addr
; if EAX >= 0, then EDI is only number-of-zeros to the right of the start of FPVal_W2.
; (What are you overwriting?)
; if EAX < 0, then EDI is number-of-zeros to the left of the start of FPVal_W2.
; (What are you overwriting?)
; ???Are you sure that's what you want???
std
rep movsb ; move the entire FPVal_W2 string, but not including the 0 byte.
cld
There are also problems with the zero stuffing.
Posted on 2003-04-22 20:11:15 by tenkey
yea, the user enters the two values. there... thats what I do before the algorithm
Posted on 2003-04-22 20:42:17 by locke
well ... I've been working on this all day. :(

What I'm TRYING to do is make it so, it fills in the shorter of the two string w/ '0's so both strings are equal in length.
Posted on 2003-04-22 20:49:57 by locke
Your main flaw is in this part of your code:
mov al, '0'
rep stosb
; write in null terminator
inc edi
mov byte ptr , 0
After filling the required number of 0s, edi is pointing at the first digit of the "short" number. You then increase the pointer by 1 and insert the terminating 0 right after that first digit!!! You can't expect to display any more than 1 digit that way.

I also can't see anywhere in your code where you check which string is the shorter one. Assuming it can be either one, and your buffers are large enough, you could look at the following code:
INVOKE Str_length, ADDR FPVal_W2

push eax ;preserve that value on the stack
INVOKE Str_length, ADDR FPVal_W1
pop ecx ;retrieve W2 length
std ;do everything backwards
.if eax > ecx ;i.e. W2<W1
lea edi,[eax+FPVal_W2]
lea esi,[ecx+FPVal_W2] ;points to the terminating 0
push ecx
inc ecx
rep movsb ;moves the terminating 0 and the digits
mov ecx,eax ;longer string length
pop eax ;shorter string length
sub ecx,eax ;difference between the two
mov al,"0"
rep stosb ;et voila!!!
.elseif ecx > eax ;W1<W2
;you can practice on this one
.endif ;if both are equal, you don't change anything
cld ;clean-up the direction flag
jmp Print
Raymond
Posted on 2003-04-22 21:09:46 by Raymond
but I do this before hand:



INVOKE Str_length, ADDR FPVal_W1
mov ecx, eax
INVOKE Str_length, ADDR FPVal_W2

cmp ecx, eax

ja Fill_Whole1 ; jump if (FPVal_W1 > FPVal_W2) to Fill_Whole1
jb Fill_Whole2 ; jump if (FPVal_W2 > FPVal_W1) to Fill_Whole2
jmp Addition1 ; jump if (FPVal_W1 == FPVwal_W2) to Addition1



it checks to see which string is the shorter one
Posted on 2003-04-22 21:20:19 by locke
What you are doing is called "padding", because you are trying to pad out the string to a certain size. I am not gonna give you any code because i am at work, and can't be bothered thinking..... but here is what you want to do:

- i am assuming that either of the strings could be the shortest

- find the length of the largest string

- allocate two chunks of memory (buffers) from the local heap (use HeapAlloc), both chunks should be the size of the largest string. As part of the allocation call you can set a flag saying the memory should be filled with zeros (NULLS)

- copy the original two strings into the new buffers, but copy them starting with the last character and moving towards the first character

- return the pointers to the new buffers


To answer your questions:

Q: Why do i suggest allocating new space for the strings?
A: Because you cannot just dynamically change the size of a string. High level languages may allow you to do that, but they achieve it by allocating new space and copying the string (or portion of the string) to the new space.

A: Why request two new chunks of memory when only one of the strings needs padding?
Q: You could do it that way, but then you need to spend a bit extra time deciding which string needs the padding, and you also have to take care to return the correct pointers at the end of the macro/function. It is just easier (although not necessarily cleaner) to just copy both strings and return the new pointers regardless of which string needed the padding.
Posted on 2003-04-22 21:36:25 by sluggy
This should fit the bill ;) (didnt test it tho, but looks right)
Function PROC  USES EBX ESI EDI  lpString1:DWORD, lpString2:DWORD

LOCAL Buffer[128] :BYTE

; Clean up the stack buffer (null first 4 bytes)
xor eax, eax
lea edx, Buffer
mov [edx], eax

; Find out which string is bigger, Make lpString1 the biggest!
invoke StrLen, lpString1
mov esi, eax
invoke StrLen, lpString2
mov edi, eax
.if( edi > esi )
mov ebx, edi
sub ebx, esi
mov esi, lpString1
mov edi, lpString2
mov lpString1, edi
mov lpString2, esi
.endif

; Save the short string (unmodified)
invoke szCatStr, addr Buffer, lpString2

; Overwrite the short buffer with needed 0's
xor eax, eax
mov esi, lpString2
mov [esi], eax
.while( ebx )
mov WORD PTR [esi], 30h
inc esi
dec ebx
.endw

; Concatonate the origional string back to the lpStrin2
inovke szCatStr, lpString2, addr Buffer

ret
Function ENDP


And no, the "WORD PTR , 30h" is no mistake. It will write both the 30h ('0') and a NULL in this order. This way i will always have a NULL when the while finishes.

Also note that writing back to the stack is perfectly ok! After all your Locals come from the same space ;)

Enjoy..
:alright:
NaN
Posted on 2003-04-22 21:38:56 by NaN
Doesn't wsprintf have a 0 padding option ?

fmtString db "-0lu",0

invoke wsprintf,ADDR buffer,ADDR fmtString ,value
Posted on 2003-04-22 21:54:04 by donkey
You really need a debugger.

Here's what happens with your new code when W1 = "123456" and W2 = "12345".
; Executed when len(W1) > len(W2)


Fill_Whole1:

; move the existing stuff
INVOKE Str_length, ADDR FPVal_W2
mov ecx, eax
INVOKE Str_length, ADDR FPVal_W1
sub eax, ecx
lea esi, [ecx + FPVal_W2 - 1]
lea edi, [eax + FPVal_W2]
std
;mov byte ptr [edi + 1],0
; I'm assuming ECX = 5 and not 6
; (that means I'm assuming Str_length is coded correctly)
; If so, EAX will be 1 at this point. [b]Can you see why?[/b]
; before movsb, bytes near FPVal_W2:
; xx xx xx xx 31 32 33 34 35 00 xx xx xx xx xx
; first byte moved (copied) is 35
; first byte moved will overwrite 32. [b]Can you see why?[/b]
; bytes are copied (read) and written one at a time
rep movsb
; after movsb, bytes near FPVal_W2:
; xx 34 35 33 34 35 33 34 35 00 xx xx xx xx xx
; Thus xxx12345 becomes 45345345 before zero stuffing
cld
Posted on 2003-04-22 21:58:41 by tenkey
Donkey, That will work as long as the strings ARE numbers. If its used for anything else, it will fail.
Posted on 2003-04-22 21:59:15 by NaN
well I have to use bytes.... your using dwords

and I'm using Masm6.15 and I don't I have the strcat function :(


Raymond:

Don't think I did the second half (the .elseif W2 > W1):



Fill_Whole1:

INVOKE Str_length, ADDR FPVal_W2
push eax ;preserve that value on the stack
INVOKE Str_length, ADDR FPVal_W1
pop ecx ;retrieve W2 length
std ;do everything backwards
.if eax > ecx ;i.e. W2<W1
lea edi,
lea esi, ;points to the terminating 0
push ecx
inc ecx
rep movsb ;moves the terminating 0 and the digits
mov ecx,eax ;longer string length
pop eax ;shorter string length
sub ecx,eax ;difference between the two
mov al,'0'
rep stosb ;et voila!!!
.elseif ecx > eax ;W1<W2
lea edi,
lea esi,
push ecx
inc ecx
rep movsb
mov ecx, eax
pop eax
sub ecx, eax
mov al,'0'
rep stosb
.endif ;if both are equal, you don't change anything
cld ;clean-up the direction flag
jmp Print

Posted on 2003-04-22 22:02:06 by locke
Funny im using 6.14. Came with Hutch's MASM32 package. If your not using the MASM32 lib you ought to be... its very handy to have.

As for DWORDS? So were you... your "INVOKE Str_length, ADDR FPVal_W1" returns a DWORD in eax. If your implying the "lpString1:DWORD" in the param line. This is the ADDRESS to the string of bytes. All addresses are DWORD length. You will notice i dont have "ADDR" in the "invoke StrLen, lpString1". This is because to call this function, it should already have the strings address passed:

invoke Function, addr MystringOfBytes, addr MyOtherStingof Bytes

:NaN:
Posted on 2003-04-22 22:11:36 by NaN
hey Donkey... thats the shortest I've seen...

How does that work??? :)


NaN: oooh... ok thanx :) forgot all near pointers are DWORDS

Though I still can't use your method b/c I don't have szCatStr
Posted on 2003-04-22 22:22:14 by locke
All *anything* pointers are DWORD in lengths (under the windows flat memory model), its why they like to coin it a 32bit operating system.

:NaN:
Posted on 2003-04-22 22:30:35 by NaN
Nan: wondering if I could use this in place of szStrCat

ncludelib KERNEL32.lib
includelib USER32.lib


lstrcat PROTO FAR PASCAL :LPSTR, :LPCSTR
Posted on 2003-04-22 22:36:32 by locke
and I'm using Masm6.15 and I don't I have the strcat function :(
Ummm, yes you do... it is part of the Windows API.....
Posted on 2003-04-22 22:49:55 by sluggy
Nan you there?


How do I implement what Donkey said:

fmtString db "-0lu",0
invoke wsprintf,ADDR buffer,ADDR fmtString ,value
Posted on 2003-04-22 22:56:13 by locke
I can't get it to work using the wsprintfA method... it shortest method and would save a lot of space... I'm not very familiar w/ ANSI.

I'd appreciate any help :)
Posted on 2003-04-23 00:27:48 by locke
Hi locke,

There is a typo there, it should say

fmtString db "%0lu",0
invoke wsprintf,ADDR buffer,ADDR fmtString ,value

replace with the width of the field and pass that as the format string to wsprintf. for example if the width of the string is 8 characters ...

.data
fmtString db "%08lu",0

.code
invoke wsprintf,ADDR buffer,ADDR fmtString ,50

; will result in buffer = "00000050"
Posted on 2003-04-23 01:48:07 by donkey