; adapted from LBEGIN by Manx Software Systems

; This routine provides the interface between the DOS loader and
; the C program. The linker fills in $MEMRY with the address of
; the first unused RAM area; control enters at $begin when the
; program is loaded. In the C86 system the corresponding routine
; is $main..............................

	include lmacros.h

codeseg segment para public 'code'
	public	$MEMRY
	public	_mbot_, _sbot_, _mtop_,_lowwater_

dataseg segment para public 'data'
$MEMRY	dw	-1
	dw	-1
	public	errno_
errno_	dw	0
	public	_dsval_,_csval_
_dsval_ dw	0
_csval_ dw	0
_mbot_	dw	0,0
_sbot_	dw	0,0
_mtop_	dw	0,0
_lowwater_	dw	-1
	public	_PSP_
_PSP_	dw	0
	extrn	_HEAPSIZ_:word,_STKSIZ_:word
	extrn	_STKLOW_:word,_STKRED_:word
	extrn	_Uorg_:byte,_Uend_:byte

; for d2io library (C) 1986, Jim Kyle, Chip Rabinowitz

	public	_ftb_
;_ftb	equ	this byte
_ftb_	dw	0ffffh			; stdin ungetc
	db	1,0,0
	dw	0ffffh			; stdout
	db	2,1,0
	dw	0ffffh			; stderr
	db	2,2,0
	dw	0ffffh			; stdlst
	db	3,3,0
	dw	0ffffh			; stdaux
	db	3,4,0
	dw	0ffffh			; first user handle
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0
	dw	0ffffh
	db	0,0,0

dem	db	0dh,0ah,'DOS version 2.x or higher required!$'
dataseg ends

exitad	dw	0
exitcs	dw	0

	assume	cs:codeseg,ds:dataseg,es:dataseg,ss:dataseg

ifdef FARPROC
	extrn Croot_:far
else
	extrn Croot_:near
endif

	public	$begin
	public	_exit_

$begin	proc	far
	mov	bp,dataseg
	test	bp,bp
	jnz	notcom
	mov	ax,253		; This CAN'T be a com file
	jmp	badexit
notcom:
	mov	ah,'0'  ;30h
	int	21h
	mov	dx,ss			;save SS value
	cmp	al,2
	jnb	dok
	mov	ds,dx
	mov	dx,offset dem
	mov	ah,9
	int	21h
	int	20h
dok:
	mov	exitcs,ds
	mov	es,bp
	mov	es:_PSP_,ds
	mov	bp,offset _Uend_ ; stack starts at Uend
	add	bp,15		; round up to next paragraph
	rcr	bp,1
	mov	cl,3		; and convert to paragraph form
	shr	bp,cl
	and	bp,01fffh
	mov	dx,es		; add in datasegment base paragraph
	add	bp,dx
	mov	bx,es:_STKRED_
	shr	bx,cl		;compute (2*STKRED)/16	note: cl==3
	cmp	bx,es:_STKSIZ_	;allocate either 2*STKRED or STKSIZ
	jae	ok1
	mov	bx,es:_STKSIZ_	;whichever is bigger
ok1:
	cmp	bx,1000h	; stack can't be bigger than 64K
	jb	ok2
	mov	bx,1000h
ok2:
	mov	dx,bx
	mov	cl,4
	shl	bx,cl
	cli
	mov	ss,bp
	mov	sp,bx
	sti
;
	add	dx,bp
	inc	dx
	mov	es:$MEMRY+2,dx	; and save as bottom of heap
	mov	es:$MEMRY,0
	mov	es:_mbot_+2,dx	; and save as bottom of heap
	mov	es:_mbot_,0
;				now adjust heap size if necessary
	mov	bx,es:_HEAPSIZ_
	add	bx,es:$MEMRY+2	; add in base paragraph of heap
	mov	es:_mtop_+2,bx	; and save as top of heap
	mov	es:_mtop_,0
	mov	si,ds
	sub	bx,si		; get size of total program in paragraphs
	mov	bp,es
	mov	es,si		; point es at PSP
	mov	ah,4ah
	int	21h		; SETBLOCK to raise or lower allocation
	jnc	didheap
	mov	ax,254
	jmp	badexit
didheap:
	mov	es,bp		; restore es to point at dataseg
;
	cld
;		clear uninitialized data
	mov	di,offset _Uorg_
	mov	cx,offset _Uend_
	sub	cx,di
	inc	cx
	shr	cx,1
	jcxz	noclear
	sub	ax,ax
rep	stosw
noclear:
;
	mov	es,[2cH]		;get enviroment segment
	sub	di,di
	mov	cx,7fffH
arglook:
	mov	ah,es:byte ptr [di]
	cmp	ah,'='                  ;look for null named env. string
	je	found_args
	test	ah,ah
	jz	no_args
repne	scasb				;look for null byte
	jz	arglook
no_args:
	mov	si,ds
	mov	es,si
	mov	si,081h
	mov	di,080h
	mov	cl,[80h]
	sub	ch,ch
	jcxz	nomov
rep	movsb
nomov:
	sub	al,al
	stosb
	mov	ax,1
	mov	di,080h
	jmp	short mov_args
;
found_args:
	sub	ax,ax
	stosb			;zap and skip over '='
mov_args:
	push	ax		; first arg # for Croot
	push	es
	push	di		; argp argument for Croot
	mov	es,bp
	mov	ds,bp		;set DS, now DS, SS, ES are equal
	mov	_dsval_,ds
	mov	_csval_,cs
	mov	ax,_STKRED_
	mov	_sbot_,ax
	call	Croot_		;Croot(argp, first)
	jmp	short exits
_exit_:
	pop	ax
	pop	ax		;fetch return code
ifdef FARPROC
	pop	ax
exit	label	far
else
exit:
endif
exits:
badexit:
	mov	ah,4cH
	int	21H
	jmp	dword ptr exitad
$begin	endp

retip	dw	0
retcs	dw	0

	public $dbgentry
$dbgentry proc far
	pop	cs:retip
	pop	cs:retcs	; save return address into debugger
	pop	ds		;set DS
	call	caller
	jmp	dword ptr cs:retip ; return to debugger
$dbgentry endp

caller	proc
	push	di		;CS value of local function
	push	si		;IP value call local function
	db	0cbH		;far return instruction
caller	endp
codeseg ends
	end	$begin
