;       SCCSID = @(#)demmac.inc	6.1 90/11/17
;	SCCSID = @(#)demmac.inc       13.10 89/04/13
;
;   Revision History:
;
;   danno   09-Nov-1988     Created
;

AsmVar	InstalledData

;***	??refer - declare external symbol in a particular segment.
;
;	Declares a symbol as an external symbol in a particular segment.
;
;	ENTRY:	sym = symbol name
;		len = one of "WORD", "DWORD"
;		    = anything else implies byte
;		seg = segment name
;
;	EXIT:	EXTRN generated for the symbol surrounded by SEGMENT/ENDS
;
;	SEE ALSO: ReferHighGlobal, ReferInitGlobal, ReferGlobal, ReferTask

??refer MACRO sym,len,seg
 &seg SEGMENT

 IFIDN <len>,<WORD>
 EXTRN &sym:WORD
 ELSE
 IFIDN <len>,<DWORD>
 EXTRN &sym:DWORD
 ELSE
 EXTRN &sym:BYTE
 ENDIF
 ENDIF

 &seg ENDS
ENDM



;***	ReferV86/I_Need - declare external symbol in the V86Data segment.
;
;	Declares a symbol as an external symbol in the V86Data segment.
;
;	ENTRY:	sym = symbol name
;		len = one of "WORD", "DWORD"
;		    = anything else implies byte
;	(global variables)
;		V86Data = segment defined in dosseg.inc
;
;	EXIT:	EXTRN generated for the symbol.
;
;	SEE ALSO: ??refer

ReferV86 MACRO sym,len
??refer sym,len,V86DATA
ENDM

I_Need	MACRO sym,len
??refer sym,len,V86DATA
ENDM

EnterCrit MACRO section
	CALL	E&section
ENDM

LeaveCrit MACRO section
	CALL	L&section
ENDM

; Re-define the "Invoke" macro, removing the EXTRN.  This speeds up
; linking and helps document external references at the beginning
; of modules

Invoke	MACRO	lbl
	CALL	lbl
	ENDM

;
;   DOSAssume
;
;   In DOS 4.x, this macro has a debug option, disabled for MVDM
;

DOSAssume   Macro   reg,reglist,message
IRP r,<reglist>
    ASSUME  r:V86GROUP
ENDM
ENDM



context macro   r
	PUSH    SS
	POP     r
	ASSUME	r:V86GROUP
endm
.xcref  context
PAGE
;
; define a data item to be public and of an appropriate size/type
;

I_AM    MACRO   name,size,init
;; declare the object public
	PUBLIC  name
;; declare the type of the object
    IFIDN <size>,<WORD>
name    LABEL WORD
	I_AM_SIZE   =   1
	I_AM_LEN    =   2
    ELSE
	IFIDN <size>,<DWORD>
name    LABEL DWORD
	I_AM_SIZE   =   2
	I_AM_LEN    =   2
	ELSE
	    IFIDN <size>,<BYTE>
name    LABEL BYTE
	I_AM_SIZE   =   1
	I_AM_LEN    =   1
	    ELSE
name    LABEL BYTE
	I_AM_SIZE   =   size
	I_AM_LEN    =   1
	    ENDIF
	ENDIF
    ENDIF
;; if no initialize then allocate blank storage
    IFB <init>
	DB  I_AM_SIZE*I_AM_LEN DUP (?)
    ELSE
IF NOT InstalledData
	IRP itm,<init>
	    IF I_AM_LEN EQ 1
		DB  itm
	    ELSE
		DW  itm
	    ENDIF
	    I_AM_SIZE = I_AM_SIZE - 1
	ENDM
	IF I_AM_SIZE NE 0
	    %out    ***** initialization of name not complete *****
	ENDIF
ELSE
	DB  I_AM_SIZE*I_AM_LEN DUP (?)
ENDIF
    ENDIF
ENDM
.xcref  I_AM
.xcref  I_AM_SIZE
.xcref  I_AM_LEN
I_AM_SIZE   = 0
I_AM_LEN    = 0


Break   <CallInstall - hook to installable pieces>

CallInstall MACRO   name,mpx,fn,save,restore
IF Installed
    IFNB    <save>
	SaveReg <save>
    ENDIF
	MOV     AX,(mpx SHL 8) + fn
	INT     2Fh
    IFNB    <restore>
	RestoreReg  <restore>
    ENDIF
ELSE
	Invoke  name
ENDIF
ENDM


;***	short_addr - declare near address
;
;	Overrides OS/2 Kernel Macro of same name
;
;	Declares a word (dw) containing the offset of the label "name"
;	from group V86GROUP. If "name" is not defined in the current
;	file, then an extrn name:near is also generated. If "name" is
;	"?", then this macro is equivalent to "dw ?".
;
;	ENTRY:	name = a label in V86GROUP group.
;
;	EXIT:	generated a word containing the offset of "name."
;
;	SEE ALSO: long_addr

CSOFFSET EQU OFFSET V86GROUP:

short_addr  MACRO   name
IFDIF	<name>,<?>
.xcref
IF2
IFNDEF name
	EXTRN	name:NEAR
ENDIF
ENDIF
.cref
	DW  CSOFFSET name
ELSE
	DW  ?
ENDIF
ENDM
.xcref	short_addr

;
; define an entry in a procedure
;
entry macro name
	PUBLIC  name
name:
endm
.xcref  entry

BREAK <ERROR - store an error code then jump to a label>

error macro code
.xcref
	mov	al,code
	transfer SYS_RET_ERR_AL
.cref
ENDM
.xcref  error

;**	SegContext - load segment register(s)
;
;	Make all given segment registers point to "base".
;
;	ENTRY:	srl	 = segment registers list in < >
;		gr	 = general register to speed operation
;			 = blank - use slow way of loading registers
;		noassume = blank - generate an assume sr:grpnam for
;				   each segment register sr
;			 = non-blank - don't generate assumes.
;		base	 = value to be loaded into segment register(s)
;		grpnam	 = name of group/segment to assume
;
;	EXIT:	code generated to load segment registers. If "gr" is
;		supplied, its content is lost.
;
;	SEE ALSO: TaskContext, DosHighContext, DosInitContext.

SegContext macro    srl,gr,noassume,base,grpnam
LOCAL i
    IFNB <gr>				;; if intermediate general register
	IFNB <base>
		mov	gr,base		;; A specific base value is given
	ELSE
		mov	gr,grpnam
	ENDIF
	IRP sr,<srl>
	    mov	    sr,gr
	ENDM
    ELSE
	IRP sr,<srl>			;; for sr = *first* segreg in list
	    i = 0
	    IRP r,<srl>			;;  for r = each segreg in list
		i = i + 1
		IF i EQ 1		;; if r is first in list
		   IFNB <base>
			push	base	;; A specific base value is given
		   ELSE
			push	grpnam	;; do push immediate
		   ENDIF
		ELSE			;; else r is second (or later) in list
		    push    sr		;; and sr contains desired value
		ENDIF
		pop	r
	    ENDM
	    EXITM			;; quit after sr = first in list
	ENDM
    ENDIF
    IFB <noassume>
	IRP sr,<srl>
		ASSUME	sr:grpnam
	ENDM
    ENDIF
endm
.xcref	SegContext


;***	DosContext - make segment register(s) point to V86GROUP
DosContext macro    srl,gr,noassume
if2
%out DosContext Macro not supported
.err
endif
endm
.xcref	DosContext


; BUGBUG danno 13-Dec-1988
; disabled until I can find a reasonable solution to this problem
TestDBCS    MACRO   nz_target
    xor     al,al
    dec     al
    ifnb     <nz_target>
    jmp     nz_target
    endif
    ENDM

BREAK <I_NEED: declare a variable external, if necessary, and allocate a size>

;
; declare a variable external and allocate a size
;
I_NEED	MACRO	sym,len
    ??refer sym,len,V86DATA
ENDM
	.xcref I_need

;

InternalError	macro	arg,lab
local a
	.386p
if IntErrF or Debug
	push	cs
	push	offset v86group:a
else
	PUSH	0
	PUSH	0
endif
	CpuMode reset
	SVC	SVC_DemInternalError
if IntErrF or Debug
V86ERRMSG segment
a	db	'&arg',0
V86ERRMSG ends
endif
ENDM
