Hi All, Merry Christmas!
I need some help on a simple replacement macro.
The offset P1 needs to convert to the actual data
from Buf. What am I missing?
I'm working on a prog. that has many second part text.
Thanks for any help.
include \masm32\include\masm32rt.inc
tstmac Macro P1
    TXT CatStr <"First part of text >,<offset P1>,< Third part of text">
   Endm
.data?
  Buf db 128 dup (?)
.code
start:
  call main
  inkey
  exit
main proc
  invoke szCopy,chr$("2nd Part"),offset Buf
  print offset Buf,10
  tstmac Buf
  print %TXT,10
  ret
main endp
end start
Pretty amazing that you can write an "assembly" program and only include one assembly language instruction (CALL) (noting that RET is actually a macro), man do I dislike useless macros, obfuscation and high level constructs. Sorry for hijacking the thread but it's a pet peeve of mine that people call that assembly language. I will go away now....
Quote from: donkey on December 08, 2007, 08:56:21 PM
RET is actually a macro
Now that you say it... how does ML distinguish between ret macro and ret opcode?
Quote from: jj2007 on December 08, 2007, 09:24:28 PM
Quote from: donkey on December 08, 2007, 08:56:21 PM
RET is actually a macro
Now that you say it... how does ML distinguish between ret macro and ret opcode?
MASM does not have to, the RET opcode is represented as RETN in MASM and most other assemblers, RET is always a macro.
xroot,
You should use string concatenation functions here.
Here's a useful multicat function I wrote for my string library.
QuotelszCatPlus:
Performs a formatted multiple concatentation
This is a C calling convention function, the caller is responsible for the stack
ECX is guaranteed to be preserved for counting loops
Parameters:
buffer = Pointer to a buffer to hold the resulting string
szFmt = Pointer to a format string that controls that concatenation
arg0..arg9 = Pointers to null term. strings or dwords, index of arg matches the format
The buffer must be large enough to hold the entire string.
szFmt has the following format:
where # is the 0 based parameter for that position
ie %[type]0 = arg0, %[type]1 = arg1 etc...
You can repeat parameters ie "%u0 %x1 %x1 %s2"
Or put them out of order "%s2 %u0 %i3 %x1"
Types:
%s# = Inserts a string pointed to by argument
%i# = Converts argument to a signed integer (i must be lower case)
%u# = Converts argument to an unsigned integer (u must be lower case)
%x# = Converts argument to a hex string (x must be lower case)
It is then followed by up to 10 arguments (0-9)
For a % sign use %%
Strings arguments are limited to a maximum of 1023 bytes
Returns the pointer to the buffer
lszCatPlus FRAME
LOCAL buffer[1024] :B
; This function is a C calling convention function (caller balances stack)
; All paramters are explicitly calculated, the following
; equates automate the process
; The following are required parameters :
pOutString = ebp+8
pFmtString = ebp+12
pOptional = ebp+16
; Preserve the Windows registers
; Preserve ECX as well so the function can easily be used
; in counted loops
push esi, edi, ebx, ecx
; truncate the string
mov eax, [pOutString]
mov B[eax], 0
; Set up the scasb parameters
invoke lszLen, [pFmtString]
mov ecx, eax
mov edi, [pFmtString]
mov esi, edi
mov eax, 025h ;"%"
L1:
REPNE scasb
or ecx, ecx
jz >>L2
push eax, ecx
; We have found a %
mov edx, edi
sub edx, esi
dec edx
lea eax, [buffer+edx]
mov B[eax], 0
; Set EAX to the end of the output string
invoke lszCopyn, offset buffer, esi, edx
invoke lszLen,[pOutString]
add eax, [pOutString]
; Append the text
invoke lszCopy, eax, offset buffer
xor edx, edx
mov dl, [edi]
cmp dl, 025h ;"%"
jne >>
; %% so just append a %
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
mov B[eax], 025h ;"%"
mov B[eax+1], 0
pop ecx, eax
inc edi
mov esi, edi
jmp <<L1
:
cmp dl,"s"
jne >>N1
mov dl, [edi+1]
cmp dl, 030h ;"0"
jl >>N1
cmp dl, 039h ;"9"
jg >>N1
sub dl, 030h ;"0"
; Calculate offset of next parameter
movzx ebx, dl
shl ebx,2
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
invoke lszCopy, eax, [pOptional+ebx] ; Next parameter
pop ecx, eax
inc edi
inc edi
mov esi, edi
jmp <<L1
N1:
cmp dl,"i"
jne >>N2
mov dl, [edi+1]
cmp dl, 030h ;"0"
jl >>N2
cmp dl, 039h ;"9"
jg >>N2
sub dl, 030h ;"0"
; Calculate offset of next parameter
movzx ebx, dl
shl ebx,2
; Convert the parameter to decimal
mov eax,[pOptional+ebx]
invoke dw2ac,eax,offset buffer
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
invoke lszCopy, eax, offset buffer ; Next parameter
pop ecx, eax
inc edi
inc edi
mov esi, edi
jmp <<L1
N2:
cmp dl,"x"
jne >>N3
mov dl, [edi+1]
cmp dl, 030h ;"0"
jl >>N3
cmp dl, 039h ;"9"
jg >>N3
sub dl, 030h ;"0"
; Calculate offset of next parameter
movzx ebx, dl
shl ebx,2
; Convert the parameter to hex
mov eax,[pOptional+ebx]
invoke dw2hx,eax,offset buffer
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
invoke lszCopy, eax, offset buffer ; Next parameter
pop ecx, eax
inc edi
inc edi
mov esi, edi
jmp <<L1
N3:
cmp dl,"u"
jne >>N4
mov dl, [edi+1]
cmp dl, 030h ;"0"
jl >>N4
cmp dl, 039h ;"9"
jg >>N4
sub dl, 030h ;"0"
; Calculate offset of next parameter
movzx ebx, dl
shl ebx,2
; Convert the parameter to hex
mov eax,[pOptional+ebx]
invoke udw2ac,eax,offset buffer
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
invoke lszCopy, eax, offset buffer ; Next parameter
pop ecx, eax
inc edi
inc edi
mov esi, edi
jmp <<L1
N4:
pop ecx, eax
mov esi, edi
jmp <<L1
L2:
; Copy the end of the string if any
; Set EAX to the end of the output string
invoke lszLen, [pOutString]
add eax, [pOutString]
invoke lszCopy, eax, esi
mov eax,[pOutString]
; Restore the Windows registers + ECX
pop ecx, ebx, edi, esi
RET
ENDF
Here's another string concatenator, which cleans its stack:
ConcatStrings: ;variable number of parms. First parm is lp_destination,
    ; and each other parm is an lp or a 1- or 2-byte ascii value
        ;Returns eax pointing at terminator
  pop ebx ;return address
  pop eax ;dest
ConcatStrings_outerloop:
  pop ecx
  jecxz ConcatStrings_done
  test ecx,0FFFF0000h ;in Windows, an address is never zero in the upper 16 bits
  jz short ConcatStrings_1or2
@@: mov dl,[ecx]
  mov [eax],dl
  inc ecx
  inc eax
  test dl,dl
  jnz @B
  dec eax
  jmp ConcatStrings_outerloop
ConcatStrings_done:
  mov [eax],cl ;zero
  jmp ebx   ;return eax pointing at terminator
ConcatStrings_1or2:
  jecxz ConcatStrings_outerloop
  mov [eax],cl
  inc eax
  shr ecx,8
  jmp short ConcatStrings_1or2
Illustration:
push 0Â ;terminator for the input to ConcatStrings
push 0A0Dh    ;cr+lf
push "]"
call @F
db "second part",0
@@:
push " "
push offset VariablePart
push " "
call @F
db "First part",0
@@:
push "["
push MyBuffer    ;lp of destination
call ConcatStrings
...
Quote from: Vortex on December 08, 2007, 09:47:40 PM
You should use string concatenation functions here.
cat$ example below. It seems that cmd$ does not behave properly, though - try the line that I commented out.
include \masm32\include\masm32rt.inc
.code
start:
invoke MessageBox,NULL,cat$(cfm$("First line\n"),cfm$("Second line\n"),cfm$("Third line with a str$: "), str$(123456)),chr$("Message"),MB_OK
invoke MessageBox,NULL,cat$(cfm$("Command line:\n"),cmd$(1)),chr$("Message"),MB_OK
; invoke MessageBox,NULL,cat$(cfm$("Command line:\n"),cmd$(1),"\nOK?"),chr$("Message"),MB_OK
invoke ExitProcess,0
end start
QuotePretty amazing that you can write an "assembly" program and only include one assembly language instruction (CALL) (noting that RET is actually a macro), man do I dislike useless macros, obfuscation and high level constructs. Sorry for hijacking the thread but it's a pet peeve of mine that people call that assembly language. I will go away now....
xroot's code may not be written in pure assembly, or pure MASM, but it is entirely in pure "MASM32" using components put together over years of package development put together buy Hutch and the community. This is after all a MASM32 forum. :U - Chris