;
; Copyright 1986 Jim Kyle and Chip Rabinowitz - All Rights Reserved
;
.xlist
	page	60,132
;
; %C86.INC -- include file for C86 use of D2IO .ASM files
;
;***************************************************************************
;
; This file provides standardized macros to generate ASM code that meets
; the C86 coding conventions.
;
; Last updated 10/27/86 -- Jim Kyle
;
; Assembler: MASM 4.0 from Microsoft
;
;	to assemble library module with listing and no symbol table:
;		MASM /N /L modnam;
;
;****************************************************************************
;

ttl	macro	modnam, vrsn, date, auth
	title	modnam -- Version vrsn -- date -- auth
	name	modnam
	subttl	(c) 1986 Jim Kyle and Chip Rabinowitz - All Rights Reserved
;
endm

;			start of data segment
dseg	macro
data	segment	para public
endm

;			define space for a pointer
defptr	macro	ptrnam
ifdef	MODEL
ptrnam	dd	0
else
ptrnam	dw	0
endif
	endm

;			declare vname as external
extv	macro	vname, type
	extrn	vname:type
endm

;			declare vname as global and initialize it
glblv	macro	vname, type, val
	havtyp = 0
	public	vname
ifidn	<type>, <byte>
vname	db	val
	havtyp = 1
endif
ifidn	<type>, <word>
vname	dw	val
	havtyp = 1
endif
ifidn	<type>, <dword>
vname	dd	val
	havtyp = 1
endif
ife	havtyp
	error -- type is unknown.
endif
	endm

glblvl	macro	list
	irp	i, <list>
	glblv	i
	endm
endm

;			end of data segment, start of code segment
cseg	macro
data	ends
;
code	segment	byte public
	assume	cs:code, ds:data, ss:data, es:data
	endm

;			declare fname as external
extf	macro	fname
	extrn	fname:near
endm

xtfs	macro	list
	irp	i, <list>
	extf	i
	endm
endm

; declare global error value
exterr	macro
	extrn	_errcod:word
endm

; set global error value
moverr	macro	val
	mov	_errcod,val
endm

; get global error value
geterr	macro	val
	mov	val,_errcod
endm

; copy global error value into stream table
saverr	macro
	push	ax
	geterr	ax
	mov	byte ptr 4[si], al
	pop	ax
endm

;			equate 'aname' to arg on stack (parameter)
darg	macro 	aname, type
;;'byte' or anything else
	havtyp	= 0
ifidn	<type>, <byte>
	aname&_v	= (_arg + 0)
	aname	equ	byte ptr aname&_v&[bp]
	_arg	= _arg + 2
	havtyp	= 1
endif
ifidn <type>, <word>
	aname&_v	= (_arg + 0)
	aname	equ	word ptr aname&_v&[bp]
	_arg	= _arg + 2
	havtyp	= 1
endif
ifidn	<type>, <dword>
	aname&_v	= (_arg + 0)
	aname	equ	dword ptr aname&_v&[bp]
	_arg	= _arg + 4
	havtyp	= 1
endif
ifidn <type>, <cdouble>
	aname&_v	= (_arg + 0)
	aname	equ	qword ptr aname&_v&[bp]
	_arg	= _arg + 8
	havtyp	= 1
endif
ifidn <type>, <ptr>
	aname&_v	= (_arg + 0)
	aname	equ	word ptr aname&_v&[bp]
	_arg	= _arg + 2
	havtyp	= 1
endif
ifidn <type>, <fptr>
	aname&_v	= (_arg + 0)
	aname	equ	word ptr aname&_v&[bp]
	_arg	= _arg + 2
	havtyp	= 1
endif
ife	havtyp
	error -- type is unknown.
endif
	endm

dargs	macro	list
	irp	i, <list>
	darg	i
	endm
endm

;			define a global procedure
procdef	macro	pname, args
	public	pname
	_arg	= 4		;;allow for BP and ret adr
	_lsz	= 2
pname	proc	near
	havreg = 0
	haveds = 0
ifb	<args>
	havbp = 0
else
	push	bp		; save frame pointer, set new one
	mov	bp, sp
	havbp	= 1
	dargs	<args>
endif
	endm

;			equate 'lvnm' to local variable
dclv	macro 	lvnm, type, asiz
;;'byte' or anything else
	havtyp	= 0
ifidn	<type>, <byte>
	_lsz	= _lsz + 1
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	byte ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <word>
	_lsz	= _lsz + 2
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	word ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn	<type>, <dword>
	_lsz	= _lsz + 4
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	dword ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <cdouble>
	_lsz	= _lsz + 8
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	qword ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <ptr>
	_lsz	= _lsz + 2
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	word ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <fptr>
	_lsz	= _lsz + 2
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	word ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <baray>
	_lsz	= _lsz + asiz
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	byte ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ifidn <type>, <iaray>
	_lsz	= _lsz + asiz + asiz
	lvnm&_v	= (0 - _lsz)
	lvnm	equ	word ptr lvnm&_v&[bp]
	havtyp	= 1
endif
ife	havtyp
	error -- type is unknown.
endif
	endm

locs	macro	list
	irp	i, <list>
	dclv	i
	endm
if	_lsz-2
	sub	sp, _lsz	; reserve AUTO variable space
endif
	endm

;			declare alt name for global procedure (alias)
alias	macro	pname, altnam
	public	altnam
altnam	label	near
	endm

;			declare alt entry to global procedure (without args)
entrdef	macro	pname
	public pname
pname:
if	havbp
	push	bp		; save frame pointer, set new one
	mov	bp, sp
endif
	endm

;			define a static procedure (internal, with args)
statdef	macro	pname, args
	_arg	= 4		;;allow for BP and ret adr
	_lsz	= 2
	havbp = 0
pname	proc	near
	havreg = 0
	haveds = 0
ifb	<args>
	havbp = 0
else
	push	bp		; save frame pointer, set new one
	mov	bp, sp
	havbp	= 1
	dargs	<args>
endif
	endm

;			begin a local procedure (without args)
internal macro	pname
pname	proc	near
	havreg = 0
	haveds = 0
	havbp = 0
endm

intrdef	macro	pname
pname	label	near
	havreg = 0
	haveds = 0
	havbp = 0
endm

callit	macro	pname,args
	argsize	= 0
ifb	<args>
else
	pushargs <args>
endif
	call	pname
if	argsize
	add	sp,argsize	; adjust stack pointer
endif
	endm

pushargs	macro list
	irp	i,<list>
	pusharg	i
	endm
	endm

pusharg macro varib,type,seg
havtyp = 0
ifidn <type>,<byte>
	push	word ptr varib&_v[bp]
	argsize = argsize + 2
	havtyp = 1
endif
ifidn <type>,<word>
	push	word ptr varib
	argsize = argsize + 2
	havtyp = 1
endif
ifidn <type>,<reg>
	push	varib
	argsize = argsize + 2
	havtyp = 1
endif
ifidn <type>,<preg>
	push	varib
	argsize = argsize + 2
	havtyp = 1
endif
ifidn <type>,<dword>
	push	word ptr varib&_v[bp+2]
	push	word ptr varib&_v[bp]
	argsize = argsize + 4
	havtyp = 1
endif
ifidn <type>,<cdouble>
	push	word ptr varib&_v[bp+6]
	push	word ptr varib&_v[bp+4]
	push	word ptr varib&_v[bp+2]
	push	word ptr varib&_v[bp]
	argsize = argsize + 8
	havtyp = 1
endif
ifidn <type>,<ptr>		;;push content of pointer
  ifdef varib&_v
	push	word ptr varib&_v[bp]
  else
	push	word ptr varib
  endif
	argsize = argsize + 2
	havtyp = 1
endif
ifidn <type>,<fptr>		;;push content of function pointer
  ifdef varib&_v
	push	word ptr varib&_v[bp]
  else
	push	word ptr varib
  endif
	argsize = argsize + 2
	havtyp = 1
endif
ife	havtyp
	error -- type is unknown.
endif
	endm

;			return values
retptrm	macro	src
	local	x1,x2
	jnc	x1
	xor	ax,ax		; return NULL
	mov	dx,ax
	jmp	short	x2
x1:	mov	ax, src		; return memory value
	mov	dx, src[2]
x2:	pret
endm

retptrr	macro	src,seg
	local	x1,x2
	jnc	x1
	xor	ax,ax		; return NULL
	mov	dx,ax
	jmp	short	x2
x1:	mov	ax,src		; return register values
	mov	dx,seg
x2:	pret
endm

retnull	macro
	sub	ax, ax
	mov	dx,ax
	pret
endm

retyes	macro
	mov	ax, 1
	pret
endm

;			pushes register variables
pushreg	macro
	push	di
	push	si
	havreg = 1
endm

;			restores bp and registers 
pret	macro
if	haveds
	pop	ds
endif
if	havreg
	pop	si
	pop	di
endif
if havbp
	mov	sp, bp		; restore SP
	pop	bp		; and frame pointer
endif
	ret
endm

;			restores register variables
popreg	macro
	pop	si
	pop	di
	havreg = 0
endm

;			end a static or internal procedure
iend	macro	pname
pname	endp
	endm

;			end a global procedure
pend	macro	pname
pname	endp
	endm

;			end of code segment
finish	macro
code	ends
	end
endm

;	other utility stuff
;
;			push/pop pairs
pushds	macro
ifdef	MODEL
	push	ds
	haveds = 1
endif
	endm

popds	macro
ifdef	MODEL
	pop	ds
	haveds = 0
endif
	endm

pushptr	macro	pointer		;;need condition if LARGE model used
	push	pointer
endm

popptr	macro	pointer
	pop	pointer
endm

;			push a local variable (relative to BP)
pshloc	macro	vnam
	push	word ptr vnam&_v[bp]
endm

;			push an argument (really same as pshloc)
psharg	macro	anam
	push	word ptr anam&_v[bp]
endm

;			this macro loads an arg pointer into DEST
ldptr	macro	dest, argname,seg
	mov	dest, argname	;;get the pointer
endm

;			this macro stores an arg pointer into DEST
svptr	macro	dest, argname,seg
	mov	argname, dest	;;store the pointer
endm

;			this macro sets PTRNAM to point to SEG:SYM
;				note that AX is destroyed
setptr	macro	ptrnam, sym, seg
	lea	ax, sym
	svptr	ax, ptrnam, seg
endm

;			this macro copies FROM to TO, both pointers
;				note that AX and DX are destroyed
ptrcpyinc	macro	from, to
	push	ax
	gwi	from
	mov	to, ax
ifdef MODEL
	gwi	from+2
	mov	to+2, ax
endif
	pop	ax
endm

extraseg	macro
	push	ds
	pop	es
endm

;			get char, unsigned, into AL and increment ptr
gci	macro	ptrnam, seg
	ldptr	si, ptrnam, seg
	cld
	lodsb
	sub	ah, ah
	svptr	si, ptrnam, seg
endm

;			get word into AX and increment ptr
gwi	macro	ptrnam, seg
	ldptr	si, ptrnam, seg
	cld
	lodsw
	svptr	si, ptrnam, seg
endm

;			put char, unsigned, from AL and increment ptr
pci	macro	ptrnam, seg
	ldptr	di, ptrnam, seg
	cld
	stosb
	svptr	di, ptrnam, seg
endm

;			put word from AX and increment ptr
pwi	macro	ptrnam, seg
	ldptr	di, ptrnam, seg
	cld
	stosw
	svptr	di, ptrnam, seg
endm

;			case test, byte
caseb	macro	val, goto
	cmp	al, val
	je	goto
endm

;			case test, word
casew	macro	val, goto
	cmp	ax, val
	je	goto
endm

.list

