;_ macros.asm
; Copyright (C) 1985-1991 by Walter Bright
; All Rights Reserved
; Modified for COFF and ELF support by David Bustin
; $Revision: 1.1.1.1 $ 

ifdef _WIN32
ifndef __NT__
__NT__ equ 1
endif
endif

ifndef M_I386

ifdef _WINDOWS
    extrn  MESSAGEFATALERROR : far
endif

; modified for RATIONAL support by P Murray, April 1990
; define DOS16RM for protected mode programs

; Determine which memory model we are assembling for. For .COM files,
; force S model.

ifdef DOS16RM
ifndef I8086L
%out	Only L model supported with RATIONAL DOS Extender.
end
endif
else
    ifdef I8086T
I8086S equ	1
    else
    ifndef I8086S
    ifndef I8086M
    ifndef I8086C
    ifndef I8086L		;if none of the memory models are defined
    ifndef I8086V
I8086S equ	1		;default to S model
    endif ;I8086V
    endif ;I8086L
    endif ;I8086C
    endif ;I8086M
    endif ;I8086S
    endif ;I8086T
endif ;DOS16RM

ifdef __OS2__
	.286C
endif


ifdef DOS16RM
	.286P
endif

ifndef I386
I386	equ	0
endif

;Decide if SI and DI are saved across function calls
SAVESIDI equ	1		;1 means SI and DI are saved across functions

if 0	;Lattice conventions no longer supported
MSC	equ	1		;ifdef means use Microsoft C calling conventions
				;ifndef means use Lattice
endif

; Macros to bracket data segment stuff.

ifndef STARTUP
begdata macro

ifdef DOS16RM
;Segment so we can find the start of DGROUP

NULL	segment para public 'BEGDATA'		;Note PARAGRAPH alignment
NULL	ends
endif

_DATA	segment word public 'DATA'
_DATA	ends
CONST	segment word public 'CONST'
CONST	ends
_BSS	segment word public 'BSS'
_BSS	ends
ifdef DOS16RM
DGROUP	group	NULL,_DATA,CONST,_BSS
else
DGROUP	group	_DATA,CONST,_BSS
endif
_DATA	segment
	assume ds:DGROUP
	endm
endif ; STARTUP

enddata macro
_DATA	ends
	endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros specific to each memory model in an attempt to make it easier
; to write memory model independent code.
;	begcode,endcode		Use to bracket code sections
;	P			Offset on BP to first argument on stack
;				(excluding any local variables)
;	SPTR			1 if small data model
;	LPTR			1 if large pointers (large data)
;	LCODE			1 if large code model
;	ESeqDS			1 if ES == DS at all times
;	SSeqDS			1 if SS == DS at all times
;	SIZEPTR			# of bytes in a pointer
;	func			Declare a function as NEAR or FAR
;	callm			Call function as NEAR or FAR

;;;;;;;;;;;;;; SMALL MEMORY MODEL ;;;;;;;;;;;;;;;;;
ifdef I8086S
begcode macro	module
_TEXT	segment word public 'CODE'
	assume	cs:_TEXT
	endm

endcode macro	module
_TEXT	ENDS
	endm

P	equ	4	; Offset of start of parameters on the stack frame
SPTR	equ	1
LPTR	equ	0
LCODE	equ	0
ESeqDS	equ	0
SSeqDS	equ	1
SIZEPTR equ	2	; Size of a pointer

p_func	macro	name
name	proc	near
	endm

p_endp	macro	name
name	endp
	endm

callp	macro	name
	call	near ptr name
	endm

func	macro	name
_&name	proc	near
    ifndef name
name	equ	_&name
    endif
	endm

callm	macro	name
	call	near ptr _&name
	endm
endif

;;;;;;;;;;;;;;;;; MEDIUM MEMORY MODEL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ifdef I8086M
begcode macro	module
module&_TEXT	segment para public 'CODE'
	assume	cs:module&_TEXT
	endm

endcode macro	module
module&_TEXT	ends
	endm

P	equ	6	; Offset of start of parameters on the stack frame
SPTR	equ	1
LPTR	equ	0
LCODE	equ	1
ESeqDS	equ	0
SSeqDS	equ	1
SIZEPTR equ	2

p_func	macro	name
name	proc	far
	endm

p_endp	macro	name
name	endp
	endm

callp	macro	name
	call	far ptr name
	endm

func	macro	name
_&name	proc	far
    ifndef name
name	equ	_&name
    endif
	endm

callm	macro	name
	call	far ptr _&name
	endm
endif

;;;;;;;;;;;;;;;;; COMPACT MEMORY MODEL ;;;;;;;;;;;;;;

ifdef I8086C
begcode macro	module
_TEXT	segment word public 'CODE'
	assume	cs:_TEXT
	endm

endcode macro	module
_TEXT	ends
	endm

P	equ	4	; Offset of start of parameters on the stack frame
SPTR	equ	0
LPTR	equ	1
LCODE	equ	0
ESeqDS	equ	0
SSeqDS	equ	0
SIZEPTR equ	4

p_func	macro	name
name	proc	near
	endm

p_endp	macro	name
name	endp
	endm

callp	macro	name
	call	near ptr name
	endm

func	macro	name
_&name	proc	near
    ifndef name
name	equ	_&name
    endif
	endm

callm	macro	name
	call	near ptr _&name
	endm
endif

;;;;;;;;;;;;;;;; LARGE MEMORY MODEL ;;;;;;;;;;;;;;;;;;;

ifdef I8086L
begcode macro	module
module&_TEXT	segment para public 'CODE'
	assume	cs:module&_TEXT
	endm

endcode macro	module
module&_TEXT	ends
	endm

P	equ	6	; Offset of start of parameters on the stack frame
SPTR	equ	0
LPTR	equ	1
LCODE	equ	1
ESeqDS	equ	0
SSeqDS	equ	0
SIZEPTR equ	4

p_func	macro	name
name	proc	far
	endm

p_endp	macro	name
name	endp
	endm

callp	macro	name
	call	far ptr name
	endm

func	macro	name
_&name	proc	far
    ifndef name
name	equ	_&name
    endif
	endm

callm	macro	name
	call	far ptr _&name
	endm
endif

;Macros to replace public, extrn, and endp for C-callable assembly routines,
; and to define labels: c_label defines labels,
; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp

c_name	macro	name
	name equ _&name
	endm

c_label macro	name
_&name:
	endm

c_public macro	a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
    ifnb <a>			;;Check for blank argument
	public	_&a
	a equ _&a
      ifnb <b>
	c_public b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
      endif
    endif
	endm

c_extrn macro	a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
    ifnb <a>			;;Check for blank argument
	extrn	_&a:b
	a equ _&a
      ifnb <c>
	c_extrn c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
      endif
    endif
	endm

c_endp	macro	name
_&name	ENDP
	endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Define function ctor as a static constructor
static_ctor macro	ctor
    if LCODE
XIFB	segment word public 'DATA'
XIFB	ends
XIF	segment word public 'DATA'
	dd	ctor
XIF	ends
XIFE	segment word public 'DATA'
XIFE	ends
    else
XIB	segment word public 'DATA'
XIB	ends
XI	segment word public 'DATA'
	dw	ctor
XI	ends
XIE	segment word public 'DATA'
XIE	ends
    endif
	endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Define function ctor as a static destructor
static_dtor macro	dtor
    if LCODE
XCFB	segment word public 'DATA'
XCFB	ends
XCF	segment word public 'DATA'
	dd	dtor
XCF	ends
XCFE	segment word public 'DATA'
XCFE	ends
    else
XCB	segment word public 'DATA'
XCB	ends
XC	segment word public 'DATA'
	dw	dtor
XC	ends
XCE	segment word public 'DATA'
XCE	ends
    endif
	endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Other more or less useful macros
; Commented out ones are obsolete

;setESeqDS macro		;set ES == DS, if not already true
;    ife ESeqDS
;	push	DS
;	pop	ES
;    endif
;	endm

.push	macro	list
	irp	arg,<list>
	 push	arg
	endm
	endm

.pop	macro	list
	irp	arg,<list>
	 pop	arg
	endm
	endm

_push	macro	list
	irp	arg,<list>
	 push	arg
	endm
	endm

_pop	macro	list
	irp	arg,<list>
	 pop	arg
	endm
	endm

; Macros to save and restore regs destroyed by a function

.save	macro	list
    if SAVESIDI
	irp	arg,<list>
	 push	arg
	endm
    endif
	endm

.restore macro	list
    if SAVESIDI
	irp	arg,<list>
	 pop	arg
	endm
    endif
	endm

_save	macro	list
    if SAVESIDI
	irp	arg,<list>
	 push	arg
	endm
    endif
	endm

_restore macro	list
    if SAVESIDI
	irp	arg,<list>
	 pop	arg
	endm
    endif
	endm

; Macros to save and restore ES, but only if ESeqDS is 1.
;pushES macro
;    if ESeqDS
;	push	ES
;    endif
;	endm
;
;popES	macro
;    if ESeqDS
;	pop	ES
;    endif
;	endm

clr	macro	list		;clear a register
	irp	reg,<list>
	 xor	reg,reg
	endm
	endm

tst	macro	reg
	test	reg,reg
	endm

jmps	macro	lbl
	jmp	short	lbl
	endm

    if @Version lt 600
	;For compatibility with MASM 5.10
.if	macro	arg1,cond,arg2,lbl
	cmp	arg1,arg2
	j&cond	lbl
	endm

    endif

_if	macro	arg1,cond,arg2,lbl
	cmp	arg1,arg2
	j&cond	lbl
	endm

;sob	macro	arg,lbl
;	ifidn	<arg>,<CX>
;	 loop	lbl
;	else
;	 dec	arg
;	 jnz	lbl
;	endif
;	endm


    ifdef _WINDOWS
    extrn  DOS3CALL : far
    endif

ifndef nobdos
bdos	macro	func
	ifnb	<func>
	mov	AH,func
	endif
    ifndef _WINDOWS
	int	21h
    else
        call	DOS3CALL
    endif
	endm

dpmi	macro	func
	ifnb	<func>
        mov	AX,func
        endif
	int	31h
        endm
else
__bdos	macro	func
	ifnb	<func>
	mov	AH,func
	endif
    ifndef _WINDOWS
	int	21h
    else
        call	DOS3CALL
    endif
	endm

__dpmi	macro	func
	ifnb	<func>
        mov	AX,func
        endif
	int	31h
        endm
endif

.retf	macro	val		;force assembler to build a far return
	ifnb	<val>
	 db	0CAh
	 dw	val
	else
	 db	0CBh
	endif
	endm

_retf	macro	val		;force assembler to build a far return
	ifnb	<val>
	 db	0CAh
	 dw	val
	else
	 db	0CBh
	endif
	endm

; Sometimes MASM ignores my segment overrides.
segES	macro
	db	26h
	endm

; 32 bit negate
neg32	macro	reg1,reg2
	 neg	reg1
	 neg	reg2
	 sbb	reg1,0
	endm

; Push immediate (reg is for scratch)
pushi	macro	reg,value
	if 0
	 push	value		;for 286 code generation only
	else
	 mov	reg,value
	 push	reg
	endif
	endm

; Inc/dec BP if I8086V memory model
incBP	macro
	ifdef I8086V
	  inc	BP
	endif
	endm

decBP	macro
	ifdef I8086V
	  dec	BP
	endif
	endm

WINENTER macro
    ifdef _WINDOWS
    ifndef I8086S
    ifndef I8086C
	inc	BP
    endif
    endif
    endif
        push	BP
        mov	BP,SP
	endm

WINLEAVE macro
	pop	BP
    ifdef _WINDOWS
    ifndef I8086S
    ifndef I8086C
        dec	BP
    endif
    endif
    endif
	endm

WINENTER_NF macro
    ifdef _WINDOWS
    ifndef I8086S
    ifndef I8086C
    	inc	BP
        push	BP
        mov	BP,SP
    endif
    endif
    endif
	endm

WINLEAVE_NF macro
    ifdef _WINDOWS
    ifndef I8086S
    ifndef I8086C
        pop	BP
        dec	BP
    endif
    endif
    endif
	endm

else	;M_I386

	.386P
	.387

ifdef DOS386
SEG_1ST_MEG	equ	034h	;Selector of 1st Mbyte used by MSDOS
SEG_SCREEN	equ	01ch	;Selector for the video memory.
SEG_PSP		equ	024H	;PSP selector.
SEG_DGROUP	equ	014H	;DGROUP selector.
SEG_ENV		equ	02cH	;Selector of environment string.

OMF	equ	1
COFF	equ	0
ELF	equ	0
_FLAT	equ	0		;FLAT memory model
_STDCALL equ	0		;default to _stdcall
_RETST0	equ	0		;return floating point results in ST0
endif	;DOS386

ifdef X386
_FLAT	equ	0
_STDCALL equ	0
_RETST0	equ	0
endif

ifdef __OS2__
OMF	equ	1
COFF	equ	0
ELF	equ	0
_FLAT	equ	1	;FLAT memory model
_STDCALL equ	1
_RETST0	equ	1
_INLINE_8087 equ 1	;defined if we always generate inline 8087 code
endif

ifdef __NT__
OMF	equ	1
COFF	equ	0
ELF	equ	0
_FLAT	equ	1
_STDCALL equ	0
_RETST0	equ	1
;_NOCTOR equ	1	;defined if no static constructors/destructors supported
_INLINE_8087 equ 1	;defined if we always generate inline 8087 code
LONGDOUBLE equ 1	;defined if memory model supports 80 bit long doubles
endif

ifdef M_XENIX
OMF	equ	1	;Set to non-zero if OMF object format.
COFF	equ	0	;Set to non-zero if COFF object format.
ELF	equ	0
_FLAT	equ	0
_STDCALL equ	0
_RETST0	equ	0
endif

ifdef M_UNIX
ifndef OMF
OMF     equ     0       ;Set to non-zero if OMF object format.
endif
ifdef M_ELF
ifndef ELF
ELF     equ     1       ;Set to non-zero if ELF object format.
endif
ifndef COFF
COFF    equ     0       ;Set to non-zero if COFF object format.
endif
else	;M_ELF
ifndef ELF
ELF     equ     0       ;Set to non-zero if ELF object format.
endif
ifndef COFF
COFF    equ     1       ;Set to non-zero if COFF object format.
endif
endif	;M_ELF
_FLAT	equ	0
_STDCALL equ	0
_RETST0	equ	0
endif

.ERRNZ	OMF AND COFF AND ELF
.ERRE	OMF OR COFF OR ELF

I386	equ	1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros specific to each memory model in an attempt to make it easier
; to write memory model independent code.
;	begcode,endcode		Use to bracket code sections
;	begdata,enddata		Use to bracket data sections
;	begrcode,endrcode       Use to bracket real mode code sections 
;	begrdata,endrdata       Use to bracket real mode data sections 
;                               (Pharlap DOS386 only)
;	P			Offset on EBP to first argument on stack
;				Assuming EBP was pushed.
;	PS			Offset on ESP to first argument on stack
;				Assuming nothing was pushed on the stack.
;	ESeqDS			1 if ES == DS at all times
;	FSeqDS			1 if FS == DS at all times
;	GSeqDS			1 if GS == DS at all times
;	SSeqDS			1 if SS == DS at all times
;	SIZEPTR			# of bytes in a pointer
;	func			Declare a function as NEAR or FAR
;	callm			Call function as NEAR or FAR
;	LPTR			Large data model?
;	SPTR			Small data model?


;Macro for start and end of real mode code segment.

begcode_16 macro     
__X386_CODESEG_16       segment para use16 public 'CODE'
        assume ds:__X386_GROUP_16
        assume cs:__X386_CODESEG_16
endm

endcode_16 macro
__X386_CODESEG_16       ends
endm

begcode macro	module
    if _FLAT
_TEXT	segment para use32 public 'CODE'
	  assume	CS:FLAT,DS:FLAT,SS:FLAT
    else
_TEXT	segment dword public 'CODE'
	  assume	CS:_TEXT
    endif
	endm

endcode macro	module
_TEXT	ENDS
	endm

begdata macro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set up segments for data
; Regular initialized data goes in _DATA

_DATA	segment dword public 'DATA'
_DATA   ends

	ifndef _NOCTOR
;Function pointers to constructors
if OMF
XIFCB	segment dword public 'DATA'
XIFCB	ends
XIFU	segment dword public 'DATA'
XIFU	ends
XIFL	segment dword public 'DATA'
XIFL	ends
XIFM	segment dword public 'DATA'
XIFM	ends
XIFCE	segment dword public 'DATA'
XIFCE	ends
XIB     segment dword public 'DATA'
XIB	ends
XI	segment dword public 'DATA'
XI	ends
XIE	segment dword public 'DATA'
XIE	ends

;Function pointers to destructors
XCB	segment dword public 'DATA'
XCB	ends
XC	segment dword public 'DATA'
XC	ends
XCE	segment dword public 'DATA'
XCE	ends

;Constant data, such as switch tables, go here.

CONST	segment dword public 'CONST'
CONST	ends
endif
;Segment for uninitialized data. This is set to 0 by the startup code/OS,
;so it does not consume room in the executable file.

_BSS	segment dword public 'BSS'
_BSS	ends

if OMF
;Function pointers to destructors
XOB	segment dword public 'BSS'
XOB	ends
XO	segment dword public 'BSS'
XO	ends
XOE	segment dword public 'BSS'
XOE	ends
endif

if OMF
ifdef DOS386
HUGE_BSS	segment dword public 'HUGE_BSS'
HUGE_BSS	ends
endif

EEND	segment dword public 'ENDBSS'
EEND	ends

ifdef DOS386
STACK	segment para stack 'STACK'
STACK	ends

DGROUP	group	_DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK
else
ifdef __OS2__
STACK	segment para stack 'STACK'
STACK	ends

DGROUP	group	_DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK
else
ifdef __NT__
STACK	segment para stack 'STACK'
STACK	ends

DGROUP	group	_DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK
else
DGROUP	group	_DATA,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND
endif	;__NT__

endif	;__OS2__
endif	;DOS386

else	;OMF
if OMF 
DGROUP	group	_DATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XOB,XO,XOE,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS
else
DGROUP	group	_DATA,_BSS
endif
endif
	endif

_DATA	segment
	if _FLAT
	  assume DS:FLAT
	else
	  assume DS:DGROUP
	endif
	endm

enddata macro
_DATA	ends
	endm

P	equ	8	; Offset of start of parameters on the stack frame
			; From EBP assuming EBP was pushed.
PS	equ	4	; Offset of start of parameters on the stack frame

			; From ESP assuming EBP was NOT pushed.
;; For Win32, ESeqDS should be TRUE
ifdef _WIN32
ESeqDS  equ     1
else
ESeqDS  equ     0
endif

FSeqDS	equ	0
GSeqDS	equ	0
SSeqDS	equ	1
SIZEPTR equ	4	; Size of a pointer
LPTR	equ	0
SPTR	equ	1
LCODE	equ	0

func	macro	name
_&name	proc	near
    ifndef name
name	equ	_&name
    endif
	endm

callm	macro	name
	call	_&name
	endm

;Macros to replace public, extrn, and endp for C-callable assembly routines,
; and to define labels: c_label defines labels,
; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp

c_name	macro	name
	name equ _&name
	endm

c_label macro	name
_&name:
	endm

c_public macro	a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
    ifnb <a>			;;Check for blank argument
	public	_&a
	a equ _&a
      ifnb <b>
	c_public b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
      endif
    endif
	endm

c_extrn macro	a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
    ifnb <a>			;;Check for blank argument
	extrn	_&a:b
	a equ _&a
      ifnb <c>
	c_extrn c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
      endif
    endif
	endm


c_endp	macro	name
_&name	ENDP
	endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Define function ctor as a static constructor
static_ctor macro	ctor
  ifndef _NOCTOR
  if 1
XIFCB	segment dword public 'DATA'
XIFCB	ends
XIFU	segment dword public 'DATA'
	;dd	ctor
XIFU	ends
XIFL	segment dword public 'DATA'
	;dd	ctor
XIFL	ends
XIFM	segment dword public 'DATA'
    if _FLAT
	dd	offset FLAT:ctor
    else
	dd	ctor
    endif
XIFM	ends
XIFCE	segment dword public 'DATA'
XIFCE	ends
    else
XIB	segment dword public 'DATA'
XIB	ends
XI	segment dword public 'DATA'
    if _FLAT
	dd	offset FLAT:ctor
    else
	dd	ctor
    endif
XI	ends
XIE	segment dword public 'DATA'
XIE	ends
  endif
  endif
	endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Define function dtor as a static destructor
static_dtor macro	dtor
  ifndef _NOCTOR
  if 1
XOB	segment dword public 'DATA'
XOB	ends
XO	segment dword public 'DATA'
    if _FLAT
	dd	offset FLAT:dtor
    else
	dd	dtor
    endif
XO	ends
XOE	segment dword public 'DATA'
XOE	ends
  else
XCB	segment dword public 'DATA'
XCB	ends
XC	segment dword public 'DATA'
    if _FLAT
	dd	offset FLAT:dtor
    else
	dd	dtor
    endif

XC	ends
XCE	segment dword public 'DATA'
XCE	ends
  endif
  endif
	endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Other more or less useful macros

;Aligns the code on dword boundary for max speed.
_align	macro
	;MASM 6.0 has a bug where ALIGN 4 produces bogus code when
	;2 or 3 bytes of filler are necessary.
	ifdef @Version
	  if @Version eq 600
	    if 0
	    if	(($ - _TEXT) and 3) eq 1
		db	08Bh,0C0h		;MOV EAX,EAX
		nop
	    else
	    if	(($ - _TEXT) and 3) eq 2
		db	08Bh,0C0h		;MOV EAX,EAX
	    else
	    if	(($ - _TEXT) and 3) eq 3
		nop
	    endif
	    endif
	    endif
	    endif
	  else
		align	4			;for MASM 5.1
	  endif
	else
		align	4			;for 386ASM
	endif
	endm

_push	macro	list
	irp	arg,<list>
	 push	arg
	endm
	endm

_pop	macro	list
	irp	arg,<list>
	 pop	arg
	endm
	endm

_if	macro	arg1,cond,arg2,lbl
	cmp	arg1,arg2
	j&cond	lbl
	endm

_ifs	macro	arg1,cond,arg2,lbl
	cmp	arg1,arg2
	j&cond	short lbl
	endm

clr	macro	list		;clear a register
	irp	reg,<list>
	 xor	reg,reg
	endm
	endm

jmps	macro	lbl
	jmp	short	lbl
	endm

tst	macro	reg
	test	reg,reg
	endm

ifndef nobdos

ifdef DOS386
bdos	macro	func		;DOS system call.
	ifnb	<func>
	 mov	AH,func
	endif
	int	21h
	endm
endif ;DOS386

ifdef X386
bdos	macro	func		;DOS system call.
	ifnb	<func>
	 mov	AH,func
	endif
	int	21h
	endm
endif ;DOS386

ifdef M_XENIX
bdos	macro	func		; 386 XENIX system call.
	ifnb	<func>
	 mov	EAX,func
	endif

	db 9ah			; call far 0x7:0
	dd 0
	dw 07h
	endm
endif ;M_XENIX

ifdef M_UNIX
bdos	macro	func		; UNIX system call.
	ifnb	<func>
	 mov	EAX,func
	endif

	db 9ah			; call far 0x7:0
	dd 0
	dw 07h
	endm
endif ;M_UNIX

endif ;nobdos

_retf	macro	val		;force assembler to build a far return
	ifnb	<val>
	 db	0CAh
	 dw	val
	else
	 db	0CBh
	endif
	endm

_ret	macro	val		;decide whether caller or callee cleans stack
	if _STDCALL
	  ret	val
	else
	  ret
	endif
	endm

; Macros to save and restore regs destroyed by a function
; Give the macro the list of registers used by the function:
;	uses	<AX,BX,SI,DI>
;
; At exit to function use 'unuse':
;	unuse	<DI,SI,BX,AX>

uses	macro	list
	irp	reg,<list>
	 ifidn	<reg>,<ebx>	;Save ebx.
	 push	reg
	 endif

	 ifidn	<reg>,<EBX>	;Save EBX (bug in ifidni).
	 push	reg
	 endif

	 ifidn	<reg>,<esi>	;Save esi.
	 push	reg
	 endif

	 ifidn	<reg>,<ESI>
	 push	reg
	 endif

	 ifidn	<reg>,<edi>	;Save edi.
	 push	reg
	 endif

	 ifidn	<reg>,<EDI>
	 push	reg
	 endif

	 ifidn	<reg>,<bx>	;Save bx.
	 push	reg
	 endif

	 ifidn	<reg>,<BX>
	 push	reg
	 endif

	 ifidn	<reg>,<si>	;Save si.
	 push	reg
	 endif

	 ifidn	<reg>,<SI>
	 push	reg
	 endif

	 ifidn	<reg>,<di>	;Save di.
	 push	reg
	 endif

	 ifidn	<reg>,<DI>
	 push	reg
	 endif

	 ifidn	<reg>,<ds>	;Save ds.
	 push	reg
	 endif

	 ifidn	<reg>,<DS>
	 push	reg
	 endif

	 ifidn	<reg>,<es>	;Save es.
	 push	reg
	 endif

	 ifidn	<reg>,<ES>
	 push	reg
	 endif
	endm
	endm

unuse	macro	list
	irp	reg,<list>
	 ifidn	<reg>,<ebx>	;Restore ebx.
	 pop	reg
	 endif

	 ifidn	<reg>,<EBX>
	 pop	reg
	 endif

	 ifidn	<reg>,<esi>	;Restore esi.
	 pop	reg
	 endif

	 ifidn	<reg>,<ESI>
	 pop	reg
	 endif

	 ifidn	<reg>,<edi>	;Restore edi.
	 pop	reg
	 endif

	 ifidn	<reg>,<EDI>
	 pop	reg
	 endif

	 ifidn	<reg>,<bx>	;Restore bx.
	 pop	reg
	 endif

	 ifidn	<reg>,<BX>
	 pop	reg
	 endif

	 ifidn	<reg>,<si>	;Restore si.
	 pop	reg
	 endif

	 ifidn	<reg>,<SI>
	 pop	reg
	 endif

	 ifidn	<reg>,<di>	;Restore di.
	 pop	reg
	 endif

	 ifidn	<reg>,<DI>
	 pop	reg
	 endif

	 ifidn	<reg>,<ds>	;Restore ds.
	 pop	reg
	 endif

	 ifidn	<reg>,<DS>
	 pop	reg
	 endif

	 ifidn	<reg>,<es>	;Restore es.
	 pop	reg
	 endif

	 ifidn	<reg>,<ES>
	 pop	reg
	 endif

	endm
	endm


endif	;M_I386

; Executable type
EXE_DOS		equ	1		; MSDOS
EXE_DOS16RM	equ	2		; Rational 286 DOS Extender
EXE_ZPM		equ	4		; ZPM 286 DOS Extender
EXE_PHAR386	equ	8		; Pharlap 386 DOS Extender
EXE_DOSX	equ	010h		; DOSX 386 DOS Extender
EXE_WINDOWS	equ	020h		; Windows 3
EXE_OS2		equ	040h		; OS/2 1.x
EXE_SCOUNIX	equ	080h		; SCO Unix
EXE_OS2_2	equ	100h		; OS/2 2.0
EXE_WINDOWSNT	equ	200h		; Windows NT

