	page	,132
	title	stdenvp - standard _setenvp routine
;***
;stdenvp.asm - standard _setenvp routine
;
;	Copyright (c) 1985-1988, Microsoft Corporation.  All rights reserved.
;
;Purpose:
;	Standard _setenvp routine.
;
;*******************************************************************************


include	version.inc
.xlist
include	cmacros.inc
include	msdos.inc
.list


sBegin	data
assumes	ds,data
externW	_psp			; PSP segment #
externDP environ 		; environment pointer

sEnd	data

sBegin	code
assumes	ds,data
assumes	cs,code

externNP _myalloc 		; allocation routine for arguments

page
;***
;_setenvp - standard routine to set envp for C programs.
;
;Purpose:
;	Reads the environment and build the envp array.
;
;Entry:
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

cProc	_setenvp,<PUBLIC>,<>

cBegin
	push	bp
	mov	ds,[_psp]	; get psp segment

assumes	ds,nothing

;	setup envp vector and move environment to heap

;	DS = PSP, SS = DGROUP

	xor	cx,cx		; cx = 0
	mov	ax,cx		; ax = 0 (search byte)
	mov	bp,cx		; bp = 0 (envp count)
	mov	di,cx		; di = 0 (initial offset)
	dec	cx		; cx = ffff (inifinite count)

	mov	si,word ptr DS:[DOS_ENVP]
	or	si,si		; test for null envp

	jz	noenv		;   none
	mov	es,si		; es:di = environment table

	cmp	byte ptr es:[0],0
	jz	noenv		; environment starts with a null byte
scanenv:
	repnz	scasb
	inc	bp		; bp = envp count
	scasb
	jnz	scanenv

noenv:
	inc	bp		; bp = envp count + 1
	xchg	ax,di		; ax = envlen
	inc	ax
	and	al,not 1	; round up to even
	mov	di,bp		; di = argument count
	shl	bp,1		; argument count*2
if	sizeD
	shl	bp,1		; argument count*2
endif
	add	ax,bp		; ax = space to allocate
	push	ss
	pop	ds		; restore DS

assumes	ds,data

; Make sure there is enough memory for the environment.
; If there is not enough, try to get some from the OS if possible.
; Register usage at this point:
;	ax = total # bytes needed for environment ptr table and strings
;	di = # of entries in env ptr table = # of env args + 1
;	bp = # bytes required to store env ptr table
;	ss = ds = DGROUP
;	es = PSP segment

	push	di		; save # of env args + 1
	mov	di,9		; error message in case of death.
	call	_myalloc	; takes bp = # bytes for ptr table ax = total #
				; bytes
	pop	di		; recover # of env args + 1


; Now there is enough memory for the environment, so copy it in.
; Register usage at this point:
;	dx = size of environment in bytes
;	di = # of entries in env ptr table = # of env args + 1
;	bp points to env table
;	ax is size of env table in bytes.
;	ss = ds = DGROUP
;	es = PSP segment


	mov	cx,di		; cx = envcnt
	mov	di,bp
	add	di,ax		; di points past env ptr table
				; store strings there
	mov	word ptr [environ],bp ; save envp[]
if	sizeD
	mov	word ptr [environ+2],ds ; segment address for large model
endif

	push	ds
	pop	es		; es:di = env dest
	mov	ds,si		; ds:0 = env table
	xor	si,si

; SS = ES = DGROUP
; DS = PSP segment

assumes	es,data
assumes	ds,nothing

	dec	cx		; adjust for the last entry of 0000
	jcxz	envdone		;   done - no environment

envloop:
	cmp	word ptr [si],';'+'C'*100h ; test if starts with ';C'
	je	envstr		; don't save pointer if ';C'

	mov	[bp],di		; save pointer to start of string
if	sizeD
	mov	[bp+2],es	; segment address for large model
	add	bp,4
else
	inc	bp
	inc	bp
endif

envstr:
	lodsb
	stosb
	or	al,al
	jnz	envstr		; keep copying string
	loop	envloop		; more strings to copy

envdone:
	mov	[bp],cx		; zero terminate envp table
if	sizeD
	mov	[bp+2],cx	; extra zero for large model
endif
	push	ss		; DS = DGROUP
	pop	ds
	pop	bp
cEnd

sEnd	code

	end
