; #########################################################################

	; ---------------------------------------------------------------
	; Kirsoft Macro Collection
	;
	; ---------------------------------------------------------------

; #########################################################################


    ; ---------------------
    ; literal string MACRO
    ; ---------------------
      literal MACRO quoted_text:VARARG
        LOCAL local_text
        .data
          local_text db quoted_text,0
        .code
        EXITM <local_text>
      ENDM
      
    ; --------------------------------
    ; string address in INVOKE format
    ; --------------------------------
      SADD MACRO quoted_text:VARARG
        EXITM <ADDR literal(quoted_text)>
      ENDM
      
    ; ------------------------------------------------------------
    ; Macro for nesting function calls in other invoke statements
    ; ------------------------------------------------------------

      FUNC MACRO parameters:VARARG
        invoke parameters
        EXITM <eax>
      ENDM

    ; --------------------------------
    ; 1. szText
    ; A macro to insert TEXT into the code section for convenient and 
    ; more intuitive coding of functions that use byte data as text.
    ; --------------------------------

      szText MACRO Name, Text:VARARG
        LOCAL lbl
          jmp lbl
            Name db Text,0
          lbl:
        ENDM

    ; --------------------------------
    ; 2. m2m
    ; There is no mnemonic to copy from one memory location to another,
    ; this macro saves repeated coding of this process and is easier to
    ; read in complex code.
    ; --------------------------------

      m2m MACRO M1, M2
        push M2
        pop  M1
        ;push eax
        ;mov eax,M2
        ;mov M1,eax
        ;pop eax
      ENDM

    ; --------------------------------
    ; 3. return
    ; Every procedure MUST have a "ret" to return the instruction
    ; pointer EIP back to the next instruction after the call that
    ; branched to it. This macro puts a return value in eax and
    ; makes the "ret" instruction on one line. It is mainly used
    ; for clear coding in complex conditionals in large branching
    ; code such as the WndProc procedure.
    ; --------------------------------

      return MACRO arg
        ;IF arg EQ 0
        ;  xor eax,eax
        ;ELSE  
          mov eax,arg
        ;ENDIF  
        ret
      ENDM

    ; --------------------------------
    ; запись нескольких строк в одну строчку
    ; --------------------------------
	@ MACRO p0,p1,p2,p3,p4,p5,p6,p7
	p0
	p1
	p2
	p3
	p4
	p5
	p6
	p7
	ENDM

    ; --------------------------------
	; копирование строки src(адр.) в tar(адр), длинной len
    ; --------------------------------
	strcpy MACRO tar,src,len
	LOCAL en,m1
	push eax
	push esi
	push edi
	push ecx
	
	mov ecx,len
	or ecx,ecx
	je  en
	mov esi,src
	mov edi,tar
	
;m1:	@<mov al,[esi]>,<mov [edi],al>,<inc esi>,<inc edi>,<dec ecx>,<jne m1>
	MemCopyF@
	
en:	pop  ecx
	pop  edi
	pop  esi
	pop  eax
	ENDM

MemCopy@ equ strcpy
	
    ; --------------------------------
	; копирование памяти вперёд из esi в edi ecx байт 
    ; --------------------------------
	MemCopyF@ MACRO
	LOCAL m1,m2
	;assume edi:NOTHING
	cld
	push ecx
    shr ecx, 2
    rep movsd
;    .if !ZERO?
;m1: @<mov eax,[esi]>,<mov [edi],eax>,<add esi,4>,<add edi,4>,<dec ecx>,<jne m1>
;	.endif
    pop ecx
    and ecx, 3
    ;rep movsb
    .if !ZERO?
m2: @<mov al,[esi]>,<mov [edi],al>,<inc esi>,<inc edi>,<dec ecx>,<jne m2>   
	.endif
    ENDM
    ; --------------------------------
    ; тоже, но направление назад
    ; --------------------------------
   	MemCopyB@ MACRO
	LOCAL m1,m2
	;assume edi:NOTHING
	std
	@<sub esi,3>,<sub edi,3>
	push ecx
    shr ecx, 2
    rep movsd
	@<add esi,3>,<add edi,3>
;    .if !ZERO?
;m1: @<mov eax,[esi]>,<mov [edi],eax>,<sub esi,4>,<sub edi,4>,<dec ecx>,<jne m1>
;	.endif
    pop ecx
    and ecx, 3
    ;rep movsb
    .if !ZERO?
m2: @<mov al,[esi]>,<mov [edi],al>,<dec esi>,<dec edi>,<dec ecx>,<jne m2>   
	.endif
    ENDM
    
    ; --------------------------------------------------
    ; Macro for placing an assembler instruction either
    ; within another or within a procedure call
    ; --------------------------------------------------

    ASM MACRO parameter1,source
      LOCAL mnemonic
      LOCAL dest
      LOCAL poz

      % poz INSTR 1,<parameter1>,< >             ;; get the space position
      mnemonic SUBSTR <parameter1>, 1, poz-1     ;; get the mnemonic
      dest SUBSTR <parameter1>, poz+1            ;; get the first argument

      mnemonic dest, source

      EXITM <dest>
    ENDM

	; --------------------------------------------------
	; ADDm & SUBm - запись в регистр результата сложения/
	;				вычитания двух переменных 
	;
	; ADDm: reg = wRec.right - swRec.right
	; SUBm: reg = wRec.right - swRec.right
	; --------------------------------------------------
	izReg MACRO reg
		IF @InStr(1,<reg>,<eax>) eq 0 AND @InStr(1,<reg>,<ebx>) eq 0 AND\
		   @InStr(1,<reg>,<ecx>) eq 0 AND @InStr(1,<reg>,<edx>) eq 0 AND\
		   @InStr(1,<reg>,<esi>) eq 0 AND @InStr(1,<reg>,<edi>) eq 0
		  EXITM <1>		; это не регистр
		ELSE
		  EXITM <0>		; это регистр
		ENDIF  
	endm
	
    ADDm MACRO reg,p1,p2
        IF izReg(reg)
    	  ;push eax
    	  mov eax,p1
    	  sub eax,p2
    	  mov reg,eax
    	  ;pop eax
    	ELSE
    	  mov reg,p1
    	  add reg,p2
    	ENDIF
    endm

    SUBm MACRO reg,p1,p2
        IF izReg(reg)
    	  ;push eax
    	  mov eax,p1
    	  sub eax,p2
    	  mov reg,eax
    	  ;pop eax
    	ELSE
    	  mov reg,p1
    	  sub reg,p2
    	ENDIF  
    endm

    ; --------------------------------------------------------
    ; MsgBox macro takes 2 parameters, both can be either
    ; literal text in quotes or addresses of zero terminated
    ; strings passed with "ADDR szString" where szString is
    ; a zero terminated string. Note that ADDR is uppercase.
    ;
    ; example : MsgBox "Greetings all",ADDR szTitle
    ;           MsgBox ADDR szMessage,"Result"
    ;
    ; --------------------------------------------------------

      MsgBox MACRO handl, TxtMsg, TxtTitle, styl

        LOCAL Msg1
        LOCAL Titl

        If @InStr(1,<TxtMsg>,<ADDR>) eq 0
          If @InStr(1,<TxtTitle>,<ADDR>) eq 0
          .data
            Msg1 db TxtMsg,0
            Titl db TxtTitle,0
          .code
            invoke MessageBox,handl,ADDR Msg1,ADDR Titl,styl
            EXITM
          EndIf
        EndIf

        If @InStr(1,<TxtMsg>,<ADDR>) gt 0
          If @InStr(1,<TxtTitle>,<ADDR>) eq 0
          .data
            Titl db TxtTitle,0
          .code
            invoke MessageBox,handl,TxtMsg,ADDR Titl,styl
            EXITM
          EndIf
        EndIf

        If @InStr(1,<TxtMsg>,<ADDR>) eq 0
          If @InStr(1,<TxtTitle>,<ADDR>) gt 0
          .data
            Msg1 db TxtMsg,0
          .code
            invoke MessageBox,handl,ADDR Msg1,TxtTitle,styl
            EXITM
          EndIf
        EndIf

        If @InStr(1,<TxtMsg>,<ADDR>) gt 0
          If @InStr(1,<TxtTitle>,<ADDR>) gt 0
            invoke MessageBox,handl,TxtMsg,TxtTitle,styl
            EXITM
          EndIf
        EndIf

      ENDM

; #########################################################################
	