This one seems to be working OK. It will take either a valid string addresses or literal text in quotes. The first argument must be a valid memory address and it will stop on an error if its not. As far as I can tell, the preprocessor does not yet support nesting macros in arguments.
; --------------------------------------------------
; count the number of arguments in a VARARG argument
; --------------------------------------------------
varargcnt MACRO args:VARARG
LOCAL cntr
cntr = 0
FOR arg,<args>
cntr = cntr + 1
ENDM
EXITM <cntr>
ENDM
showit MACRO args:VARARG
LOCAL var
var = varargcnt(args)
.echo var
ENDM
cat$ MACRO pmem,args:VARARG
LOCAL var
LOCAL strng
IF (OPATTR pmem) AND 8000h
ECHO ---------------------------------------------------------
ECHO cat$().ERROR First operand must be a valid memory address
ECHO ---------------------------------------------------------
.err
ENDIF
var = varargcnt(args)
strng equ <szMultiCat,var,pmem>
FOR arg,<args>
strng CATSTR strng,<,>,reparg(arg)
ENDM
invoke strng
EXITM <eax>
ENDM
Here is the test code used with it.
main proc
LOCAL arg1 :DWORD
LOCAL arg2 :DWORD
LOCAL pmem :DWORD
LOCAL buffer[256]:BYTE
cls
mov pmem, ptr$(buffer)
mov arg1, str$(1234)
mov arg2, str$(5678)
print cat$(pmem,"text ",arg1," more ",arg2,"\n") ; correct
; print cat$("text","text ",arg1," more ",arg2,"\n") ; user error
ret
main endp