The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: jj2007 on December 11, 2007, 11:06:21 PM

Title: szMultiCat
Post by: jj2007 on December 11, 2007, 11:06:21 PM
In the course of learning the use of macros, I stumbled over the following:


.nolist
include \masm32\include\masm32rt.inc

CrLf EQU 13,10

.data?
pBuf dd ?
StrBuffer db 256 dup (?)

.code

start:
  invoke SetConsoleTitle,chr$("szMultiCat test:")

  mov pBuf,offset StrBuffer
  print rv(szMultiCat,2,pBuf, chr$(CrLf,CrLf,"Test 1:"), str$(1))
  print rv(szMultiCat,2,pBuf, chr$(CrLf,"Test 2:"), str$(2))
  print rv(szMultiCat,2,pBuf, chr$(CrLf,"Test 3:"), str$(3))
  call ret_key
  invoke ExitProcess,0
end start


The three print statements produce the following output:

Test 1:1

Test 1:1
Test 2:2

Test 1:1
Test 2:2
Test 3:3


In a nutshell: szMultiCat appends strings to what it finds in pBuf resp. StrBuffer
To produce the desired behaviour, i.e. new text for every "print", one would have to poke
a zero byte into pBuf. So I wrote an adaptation of szMultiCat called cs2b, "concat string to buffer"
In contrast to szMultiCat, cs2b will always write the first string to the start of the buffer.
Source code and exe are attached. Don't get scared by the length of certain code lines - I am
just testing the limits of macros.

QUESTION: Am I reinventing the wheel? Is there already a macro or function with this behaviour?

P.S.: I also attach my latest AsmBuild, fixing a tiny bug (a reappearing message box asking whether this was a console app - now it will ask only once)

[attachment deleted by admin]
Title: Re: szMultiCat
Post by: MichaelW on December 12, 2007, 05:50:32 AM
I know of no single macro or procedure that will do this, but you could make a function version of the zero1 macro and use it inline.

zero$ MACRO membuf
  mov membuf[0], 0
  EXITM <ADDR membuf>
ENDM

print cat$(zero$(buff),cfm$("\n\nTest 1:"),str$(1))
print cat$(zero$(buff),cfm$("\n\nTest 2:"),str$(2))
print cat$(zero$(buff),cfm$("\n\nTest 3:"),str$(3),cfm$("\n\n"))

Title: Re: szMultiCat
Post by: jj2007 on December 12, 2007, 08:53:47 AM
Thanks, Michael, that was very helpful  :thumbu

However, cat$ seems to work even without the zero$ macro, at least on my machine... ::)
The High Level Reference help says (confirming your post) "the first byte MUST be set to a
zero byte". The behaviour I observe with the code posted below is different...
I also don't understand why the help calls lpBuffer the source buffer - shouldn't that be destination buffer?

Cheers, jj

cat$
mov lpbuffer, cat$(lpBuffer,[variable number of strings])

Description
Concantenate multiple string into a single buffer.

Parameters
   1. lpBuffer The address of the source buffer to append other strings to.
   2. A variable number of string addresses to append to the source buffer.

Return Value
The return value is the address of the source buffer that can be assigned back to itself or to another pointer (string handle).

Comments
This is a very flexible and useful macro that can handle multiple strings in different formats.
If the source buffer does not already have string data in it, the first byte MUST be set to a
zero byte so it is seen as a zero length string. The source string buffer must be large enough
to receive all of the string data appended to it.


include \masm32\include\masm32rt.inc

CrLf EQU 13,10
zero$ MACRO membuf
  mov membuf[0], 0
  EXITM <ADDR membuf>
ENDM

.code

start: invoke SetConsoleTitle,chr$("String testing")
call TestProc
call ret_key
invoke ExitProcess,0

TestProc proc
LOCAL buffer[1024]:BYTE ; max 32000 bytes
LOCAL pBuf:DWORD

lea eax, buffer
mov pBuf,eax

print cat$(zero$(pBuf),cfm$("\nTest 1:"),str$(1))
print cat$(zero$(pBuf),cfm$("\nTest 2:"),str$(2))
print cat$(zero$(pBuf),cfm$("\nTest 3:"),str$(3),cfm$("\n"))

print cat$(cfm$("\nTest 4:"),str$(4))
print cat$(cfm$("\nTest 5:"),str$(5))
print cat$(cfm$("\nTest 6:"),str$(6),cfm$("\n"))

ret

TestProc endp
end start
Title: Re: szMultiCat
Post by: jj2007 on December 12, 2007, 09:44:48 AM
Just to confirm that cat$ does the job, and is 6 bytes shorter than my cs2b modification of szMultiCat.

39 bytes each:
print cat$(chr$(CrLf,"Test "), chr$("line"))

45 bytes each:
print rv(cs2b,2,pBuf, chr$(CrLf,"Test "), chr$("line"))

Thanks also for pointing me to cfm$. Really handy.
Title: Re: szMultiCat
Post by: MichaelW on December 12, 2007, 06:50:42 PM
QuoteHowever, cat$ seems to work even without the zero$ macro, at least on my machine... ::)

I used cat$ because it was easier to type than rv(szMultiCat… (IOW because I’m lazy), assuming that it would work the same, and now that I test it, it does.

print cat$(zero$(buff),cfm$("\n\nTest 1:"),str$(1))
print cat$(zero$(buff),cfm$("\n\nTest 2:"),str$(2))
print cat$(zero$(buff),cfm$("\n\nTest 3:"),str$(3),cfm$("\n\n"))


Test 1:1

Test 2:2

Test 3:3


print cat$(ADDR buff,cfm$("\n\nTest 1:"),str$(1))
print cat$(ADDR buff,cfm$("\n\nTest 2:"),str$(2))
print cat$(ADDR buff,cfm$("\n\nTest 3:"),str$(3),cfm$("\n\n"))


Test 1:1

Test 1:1

Test 2:2

Test 1:1

Test 2:2

Test 3:3


Also, the zero$(pBuf) will cause cat$ to use a buffer that starts at the address of pBuf, overwriting anything that follows and/or causing an exception.

And cat$(cfm$("\nTest 4:"),str$(4)) will cause cat$ to write past the end of the data allocated by cfm$.
Title: Re: szMultiCat
Post by: jj2007 on December 12, 2007, 08:39:53 PM
Quote from: MichaelW on December 12, 2007, 06:50:42 PM
QuoteHowever, cat$ seems to work even without the zero$ macro, at least on my machine... ::)
And cat$(cfm$("\nTest 4:"),str$(4)) will cause cat$ to write past the end of the data allocated by cfm$.
Yep, you are right :red
That's why "it works" as I wanted it to work - cfm$ allocates a fresh buffer every time. In real life, it seems to tolerate about 2k of string len before it produces a GPF. I tried to understand where it allocates the buffer but got a bit lost... what does "buffer CATSTR buffer,..." mean (in macros.asm)? Is CATSTR an EQU?
Title: Re: szMultiCat
Post by: MichaelW on December 12, 2007, 09:18:19 PM
See Chapter 9, Using Macros, of the MASM Programmer’s Guide, available  here (http://webster.cs.ucr.edu/Page_TechDocs/index.html).