;-----------------------------------------
; This file is part of Fresh standard
; macro library.
;-----------------------------------------

 INIT@CHAIN = 0


macro locals {
  local ..locsize
  locsize equ ..locsize
  virtual at ebp - ..locsize - .__info.commonframe.size
  @@:
}


macro endl {
  rb (4 - ($- @b) and 11b) and 11b
  locsize = $ - @b
  if $-@b > maxsize
    maxsize = $-@b
  end if
  end virtual
  restore locsize
}


macro err@endp { }


macro proc name, [arg] {
  common
    \err@endp

    macro err@endp \{
      end if
      Missing 'endp' or 'endwp' before the procedure.
    \}

    if ~ used name
      if defined options.ShowSkipped & options.ShowSkipped
        display 1,'Procedure skiped: ',`name, $0d, $0a
      end if
    else

  name:
    .__info.id = 1

    virtual at ebp+8
      if ~ arg eq
        forward
          arg dd ?
          if ~ defined name#arg
            ERROR! the argument `arg MUST begins with dot
          end if
        common
      end if
        .__info.argsize = $-ebp-8
    end virtual

    virtual at ebp - .__info.commonframe.size
    .__info.commonframe.begin:
}


macro begin {
      rb (4 - ($ - .__info.commonframe.begin) and 11b) and 11b
      .__info.commonframe.size = $ - .__info.commonframe.begin
    end virtual

    local ..maxsize
    maxsize equ ..maxsize
    ..maxsize = 0

    if .__info.framesize
      if defined options.FastEnter & options.FastEnter
        push ebp
        mov  ebp, esp
        sub  esp, .__info.framesize
      else
        enter .__info.framesize, 0
      end if
    else
      if .__info.argsize
        push ebp
        mov  ebp, esp
      end if
    end if
}


macro cret {
  if .__info.argsize | .__info.framesize
    if ..FastEnter
      mov   esp, ebp
      pop   ebp
    else
      leave
    end if
  end if
  retn
}


macro return {
  if .__info.argsize | .__info.framesize
    if defined options.FastEnter & options.FastEnter
      mov   esp, ebp
      pop   ebp
    else
      leave
    end if
  end if

  if .__info.argsize
    retn .__info.argsize
  else
    retn
  end if
}



macro endp {
    .__info.framesize = maxsize + .__info.commonframe.size
  end if
  restore maxsize
  purge err@endp
}



macro winproc name, [arg] {
common

  \err@endp

  macro err@endp \{
    end if
    Missing 'endp' or 'endwp' before the procedure.
  \}


  if ~ used name
    if defined options.ShowSkipped & options.ShowSkipped
      display 1,'Message procedure skiped: ',`name, $0d, $0a
    end if
  else

 name:
    .__info.id = 2

  if arg eq
    virtual at ebp+8
      .hwnd dd ?
      .wmsg dd ?
      .wparam dd ?
      .lparam dd ?
      .__info.argsize = 16
    end virtual
  else
    virtual at ebp+8
      forward
        arg dd ?
        if ~ defined name#arg
          ERROR! the argument `arg MUST begin with dot
        end if
      common
        .__info.argsize = $ - ebp - 8
    end virtual
  end if

  if .__info.argsize <> 16
    Error! The count of `name arguments MUST be 4 dwords.
  end if

  virtual at ebp - .__info.commonframe.size
  .__info.commonframe.begin:
}



macro ondefault {  ; begins procedure instructions
  common
    local ..msgcounter, ..msglist
    msgcounter equ ..msgcounter
    msglist equ ..msglist

    ..msgcounter = 0

    call JumpTo
    ..msglist:
    rd   .__info.msgcount
    dd   0

    .ondefault:
}


macro onmessage message {
  .#message:
  .#message#.__info.id = 3
  .#message#.__info.number = msgcounter / 4
     store word message at (msglist + msgcounter)
     store word ($ - msglist - msgcounter - 4 ) at (msglist + msgcounter + 2)
  msgcounter = msgcounter + 4
}


macro endwp {
    .__info.msgcount = msgcounter / 4
    .__info.framesize = maxsize + .__info.commonframe.size
  end if
  restore maxsize, msgcounter, msglist
  purge err@endp
}


macro initialize procname {
  INIT@CHAIN equ INIT@CHAIN, procname
  proc procname
}

macro finalize procname {
  FINISH@CHAIN equ FINISH@CHAIN,procname
  proc procname
}

;macro callchain dummy, [arg] {
;common
;   call dummy
;forward
;   call arg
;}

macro InitializeAll {
  macro INIT@CHAIN dummy, [n] \{
  \forward
    call n
  \}

  match I, INIT@CHAIN \{
    I
  \}
}

macro FinalizeAll {
  macro FINISH@CHAIN dummy, [n] \{
  \forward
    if n eqtype 1234
    call n
    end if
  \}

  match F, FINISH@CHAIN \{
    F
  \}
}


;*****************************************
; Call macroses
;*****************************************

macro stdcall proc, [arg] {    ; call procedure
common
  local ..argsize
  ..argsize = 0
  if ~ arg eq
reverse
    pushd arg
    ..argsize = ..argsize + 4
common
  end if
  if defined options.CheckArguments & options.CheckArguments
    if (defined proc#.__info.argsize) & (proc#.__info.argsize <> ..argsize)
      ERROR! wrong argument count for procedure call.
    end if
  end if

  call proc
}


macro invoke proc,[arg] {   ; invoke procedure (indirect)
common
  if ~ arg eq
reverse
    pushd arg
common
  end if
  call [proc]
}


macro ccall proc,[arg]                  ; call procedure in C calling convention
 { common local ..size
   ..size = 0
   reverse
   pushd arg
   ..size = ..size+4
   common
   call proc
   add esp,..size }

macro cinvoke proc,[arg]                ; invoke procedure (indirect)
 { common
    if ~ arg eq
     ccall [proc],arg
    else
     call [proc]
    end if }


;****************************************
; INT3 break point, when first = second.
;****************************************

macro BreakEq first, second {
  local .lbl
  push  eax
  mov   eax, first
  cmp   eax, second
  pop   eax
  jne   .lbl

  int3

.lbl:
}
