News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Macro CatStr

Started by xroot, December 08, 2007, 08:47:30 PM

Previous topic - Next topic

xroot

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

donkey

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....
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

jj2007

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?

donkey

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.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Vortex

xroot,

You should use string concatenation functions here.

donkey

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
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Larry Hammick

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
...


jj2007

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

ChrisLeslie

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