;    File              : $Workfile: CSUP.ASM$
;
;    Description       :
;
;    Original Author   : DIGITAL RESEARCH
;
;    Last Edited By    : $CALDERA$
;
;-----------------------------------------------------------------------;
;    Copyright Work of Caldera, Inc. All Rights Reserved.
;      
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
;    CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
;    *** Current Edit History ***
;    *** End of Current Edit History ***
;
;    $Log$
;    ENDLOG
;
; 28 Jan 88 Change the validation check for the environment. Now we look
;		for a valid DOS Memory Descriptor which is owned by the 
;		Command Processor.
; 12 May 88 Handle Empty environments correctly (Thanks DesqView)
; 26 May 88 ach _stack is only defined for MSC
; 16 Jun 88 Support TURBO C Stack checking and enable CHKSTK for
;       MSC only.
; 26 Aug 88 Make the Minimum Stack Address Public
; 14 Apr 89 Make heap_top public
; 14 Jul 89 Move findeof to assembler
; 09 Oct 90 Write heap_size() to return remaining bytes on heap at 
;               any given instance
;

_DLS_INCLS_	equ	1
include	message.def

CGROUP	GROUP	_TEXT
DGROUP	GROUP	_DATA

codeOFFSET	equ	offset CGROUP:
dataOFFSET	equ	offset DGROUP:
STACKSLOP	equ	128		; Minimum Stack Size

jmps	macro	label			; Define a Macro to generate the
	jmp	SHORT label		; Short Jmp instruction
	endm


_TEXT	SEGMENT	byte public 'CODE'
ifdef	MWC
	extrn	longjmp:near		; MetaWare does not preceed library
LONGJUMP	equ	longjmp		; functions with an UNDERSCORE
else
ifdef	WATCOMC
	extrn	longjmp_:near
LONGJUMP	equ	longjmp_
else
	extrn	_longjmp:near
LONGJUMP	equ	_longjmp
endif
endif

	assume	cs:CGROUP, ds:DGROUP, es:nothing

	public	_debug
_debug	proc near
	
	out	0fdh,al
	ret

_debug	endp


;	Environment manipulation routines
;	=================================
;
;BOOLEAN	env_entry(BYTE *buf, WORD entry);
;
;		Copy entry number ENTRY into the buffer BUF. Return FAILURE
;		if ENTRY cannot be found.
;
	assume	cs:CGROUP, ds:DGROUP, es:nothing

	public	_env_entry
_env_entry	PROC	near
	cld
	push	bp
	mov	bp,sp
	push	ds
	push	si
	push	es
	push	di
	call	get_env			; Get the environment segment
	mov	es,bx			; Initialise ES
	mov	cx,ax			; Check the environment size - 1 
	dec	cx			; and FFFF bytes if no env header 
	xor	di,di			; Offset to start scaning for data
	xor	ax,ax
env_e10:
	cmp	es:byte ptr [di],al	; Is this a Null string
	jz	env_fail		; Then hit the end of the search
	cmp	word ptr 06[bp],0	; Is this the entry required
	jz	env_e20
	repnz	scasb			; Scan for the next zero byte
	jcxz	env_fail		; and abort if out of space 
	dec	word ptr 06[bp]		; Decrement the string count
	jmps	env_e10
env_e20:				; Found the correct entry now copy
	mov	si,di			; Get the correct source offset
	push ds
	push es
	pop ds
	pop es
	mov	di,04[bp]
env_e30:
	lodsb
	stosb				; Copy byte through AL
	or	al,al
	jnz	env_e30			; and check for end of string
	jmps	env_exit
_env_entry	ENDP

;BOOLEAN	env_scan(BYTE *key, BYTE *buf);
;
;	Scan through the environment searching for the string KEY then copy
;	the result into buffer.

	Public _env_scan
_env_scan	PROC	near
	cld
	push	bp
	mov	bp,sp
	push	ds
	push	si
	push	es
	push	di
	call	get_env			; Get the environment segment
	call	get_key			; Find the key
	jz	env_fail		; Abort if an error occurs
	add	di,dx			; Add the Key length and just copy
	mov	si,di			; The key definition into the 
	push ds				; Buffer
	push es
	pop ds
	pop es
	mov	di,06[bp]
env_s10:
	lodsb 
	stosb				; Copy byte through AL
	or	al,al
	jnz	env_s10			; and check for end of string
	jmps	env_exit
_env_scan	ENDP

;
;	Environment handling exit routines

env_err:				; Invalid Environment descriptor
	mov	ax,-1			; return with -1
	jmps	env_ret

env_fail:				; Environment fail the operation 
	mov	ax,1			; requested has failed.
	jmps	env_ret

env_exit:
	xor	ax,ax

env_ret	PROC	near
	pop	di
	pop	es
	pop	si
	pop	ds
	pop	bp
	ret
env_ret	ENDP

;
;BOOLEAN	env_del(BYTE *key);
;	Delete the entry matching  KEY from the environment and return
;	success or failure
;
	public	_env_del
_env_del	PROC	near
	cld
	push	bp
	mov	bp,sp
	push	ds
	push	si
	push	es
	push	di
	call	get_env			; Get the environment segment
	jz	env_err			; Stop if not the real thing
	call	get_key			; Find the key
	jz	env_fail		; Abort if an error occurs
	mov	ds,bx			; Point DS at the environment
	mov	si,di			; save the destination offset
	add	di,dx			; and search for the end of this string
	xor	ax,ax
	mov	cx,-1
	repnz	scasb			; Now search for the end of string
	xchg	si,di			; Swap the source and destination
env_d10:
	cmp	al,[si]			; Is this the end of the environment
	jz	env_d20			; Yes so terminate
env_d15:
	lodsb
	stosb				; Copy through AL checking for the end
	or	al,al
	jnz	env_d15			; of the environment after each
	jmps	env_d10			; end of string.
env_d20:
	stosw				; Force 0 word to be placed here to 
	jmps	env_exit		; terminate the string
_env_del	ENDP

;BOOLEAN	env_ins(BYTE *str);
;		Insert the string at the end of the current environment
;		checking if there is enough room to save the string.
;
	public _env_ins
_env_ins	PROC	near
	cld
	push	bp
	mov	bp,sp
	push	ds
	push	si
	push	es
	push	di
	call	get_env			; Get the environment segment
	jz	env_err			; and its segment
	sub	ax,2			; Decrement the size of the env
	mov	cx,ax			; to make sure we can store a 0
	xor	ax,ax			; word terminator
	mov	es,bx			; Find the end of the current env
	xor	di,di
env_i10:
	repnz	scasb
	jcxz	env_fail
	cmp	al,es:byte ptr [di]
	jnz	env_i10
	cmp	di,1			; Is this an empty Environment
	jnz	env_i25			; No. If yes then start from offset 0
	dec	di
env_i25:
	mov	bx,di			; Save the starting address of string
	mov	si,04[bp]		; Get the source string offset
env_i20:
	lodsb
	stosb				; Copy the String until a zero byte
	or	al,al			; then add the environment terminator
	loopnz	env_i20
	mov	es:word ptr [di],0
	jz	env_exit		; Exit with no error if the string is
	mov	es:byte ptr [bx],00	; terminated correctly otherwise remove
	jmps	env_fail		; all traces of this string and exit
_env_ins	ENDP
;
	page
;
;	Returns environment size in Bytes in AX or zero if error
;	and BX is the Environment segment.
;
get_env	PROC	near
	push	es
	mov	dx,__psp		; Get the Current PSP in DX
	mov	es,dx			; and point ES at Our PSP
	xor	ax,ax			; and assume an error condition
	mov	bx,es:002Ch		; get environment segment
	dec	bx			; Check for memory descriptor
	mov	es,bx
	inc	bx
	cmp	es:byte ptr 00h,'M'	; Byte 0 must contains either an 
	jz	get_e10			; M or Z and the DMD be owned by
	cmp	es:byte ptr 00h,'Z'	; the Command Processor
	jnz	get_e20
get_e10:
if 0
	cmp	dx,es:word ptr 1h	; Is this "OUR" PSP if not then
	jnz	get_e20			; complain bitterly.
endif
	mov	ax,es:word ptr 3h	; Get the memory size in paragraphs
	shl	ax,1			; convert to size in bytes and exit.
	shl	ax,1
	shl	ax,1
	shl	ax,1
get_e20:
	pop	es
	or	ax,ax
	ret
get_env	ENDP

;
;	enter this search function with BX == ENVIRONMENT SEGMENT
;					04[bp] == Key string offset
;	On exit	AX == 0 Failure
;		else	DX is Key string Length
;			DI is Offset
;
get_key	PROC	near
	push ds
	pop es				; Calculate the length of the 
	mov	di,04[bp]		; key by scaning the string for
	mov	al,0			; a zero byte.
	mov	cx,-1
	repnz	scasb
	neg	cx			; CX is the length of the sting + 2
	sub	cx,2
	mov	dx,cx			; Save the count in dx
	
	xor	ax,ax
	mov	es,bx			; Point ES at the environment
	xor	di,di			; and start from the begining
get_k10:
	push	di			; Save incase this is a match
	mov	cx,dx			; Get the string length
	mov	si,04[bp]		; and offset and check for a match
	repz	cmpsb
	jnz	get_k20			; No match so get the next string
	pop	di			; This is the starting offset
	or	ax,-1			; All ok
	ret
get_k20:
	pop	cx			; Throw away the old DI
	mov	cx,-1			; Set the count to maximum
	repnz	scasb			; and search for the end of the string
	cmp	al,es:[di]		; exit with error if this is the end
	jnz	get_k10			; of the environment
	ret
get_key	ENDP

	page
	assume	cs:CGROUP, ds:DGROUP, es:nothing
ifdef MSC
;
;
;	STACK(WORD) allocates memory from the C STACK if at any stage
;	the stack grows to within STACKSLOP of the top of the heap this
;	function executes a LONGJUMP using the BREAK_ENV buffer. This will
;	terminate any internal function.
;
PUBLIC	_stack
_stack:
	pop	bx			; Get the return address
	pop	cx			; and the number of bytes required
	add	cx,1			; Force CX to be a even value to
	and	cx,not 1		; ensure the stack is word aligned
	mov	ax,sp			; Get the Stack
	sub	ax,STACKSLOP		; Include STACKSLOP
	sub	ax,cx			; Subtract requested buffer
	jc	heap_error		; Exit with error if Carry
	cmp	ax,heap_top		; Are we still above the heap
	jc	heap_error		; No
	pop	ax			; Get possible saved SI
	pop	dx			; Get possible saved DI
	push	dx			; Restore the stack to its
	push	ax			; origibnal format	
	sub	sp,cx			; All OK so update SP
	push	dx			; Save possible saved DI
	push	ax			; Save possible saved SI
	mov	ax,sp			; Return pointer
	add	ax,4			; Adjust pointer for saved SI/DI
	push	cx			; Restore the entry parameter
	jmp	bx			; and return to the caller
endif
;
;	HEAP_GET(WORD) allocates memory from the C HEAP if at any stage
;	the heap grows to within STACKSLOP of the base of the stack this
;	function executes a LONGJUMP using the BREAK_ENV buffer. This will
;	terminate any internal function.
;
PUBLIC	_heap_get
_heap_get:
	push	bp
	mov	bp,sp
	mov	ax,heap_top
	add	ax,04[bp]		; Add in the requested value
	jc	heap_error		; Exit with error if Carry
	sub	bp,STACKSLOP		; now check that the stack
	cmp	bp,ax			; is still well above the 
	jc	heap_error		; heap.
	mov	stack_min,ax		; Update the Stack Minimum Variable
	add	stack_min,STACKSLOP	; for the CHKSTK routine
	
	xchg	ax,heap_top		; Return the existing heap top
	pop	bp			; and update the local variable
	ret				; with the new value.

heap_error:
	mov	dx,3			; Return the Heap Overflow error
	push	dx
	mov	ax,dataOFFSET _break_env ; using the JMP_BUF
	push	ax
	call	LONGJUMP			; We are never coming back

;
;	HEAP_SIZE returns the size remaining on the C HEAP 
;
PUBLIC	_heap_size
_heap_size:
	push	bp
	mov	bp,sp
	mov	ax,heap_top
        add     ax,STACKSLOP
	sub	bp,ax		
        jnc     noprobs
        xor     bp,bp
noprobs:
	mov	ax,sp		
	pop	bp		
	ret			

;
;	HEAP() can only return a pointer to the top of the C Heap
;	and is identical in function to HEAP_GET(0) except that no
;	overflow checking is required and the calling overhead is 
;	minimal.
;
PUBLIC	_heap
_heap:
	mov	ax,heap_top
ifndef FINAL
ifdef WATCOMC
	add	ax,STACKSLOP	; we'd better do some stack checking
	cmp	ax,sp		; 'cause the C isn't doing it now
	 jae	heap_error
	sub	ax,STACKSLOP
endif
endif
	ret
	
;
;	VOID HEAP_SET(BYTE *) forces the heap to a specified value
;
PUBLIC	_heap_set
_heap_set:
	push	bp
	mov	bp,sp
	mov	ax,04[bp]		; Get the new value for the HEAP
	cmp	ax,dataOFFSET _end	; base and check against the 
	jnb	heap_s10		; absolute base. If below then force
	mov	ax,dataOFFSET _end	; the heap to the absolute base
heap_s10:
	mov	heap_top,ax	
	mov	stack_min,ax
	add	stack_min,STACKSLOP
	pop	bp
	ret

	page
ifdef MSC
;
;	This is our own Stack Check routine which is called on 
;	entry to every C routine. AX contains the number of bytes
;	to be reseved on the stack.
;
PUBLIC	__chkstk
__chkstk:
	pop	cx		; Get the Return Address

	mov	bx,sp		; Calculate the new SP value
	sub	bx,ax		; AX contains the number of bytes
	jc	OVERFLOW@	; to reserve.

	cmp	bx,stack_min	; Check we are still above the heap
	jc	OVERFLOW@	; No !!! Help
	mov	sp,bx		; Update the Stack pointer
	jmp	cx		; Its Ok lets go back
endif

ifdef WATCOMC
	Public	__STK
__STK:
	cmp	ax,sp
	 jnb	OVERFLOW@
	sub	ax,sp
	neg	ax
	cmp	ax,stack_min
	 jbe	OVERFLOW@
	ret
endif

ifdef TURBOC
	Public	OVERFLOW@		; Public TURBOC Stack Error Handler
endif
OVERFLOW@:
	mov	dx,2			; Return the STACK Overflow error
	push	dx
	mov	ax,dataOFFSET _break_env ; using the JMP_BUF
	push	ax
	call	LONGJUMP		; We are never coming back

; MLOCAL UWORD CDECL findeof(s, count)		/* find ^Z in buffer	   */
; BYTE FAR   *s;					/* buffer to search	   */
; UWORD  count;					/* # of bytes in buffer    */
; {
; REG UWORD i;
; 
; 	i = count;
; 	while(i) {				/* Scan through the data   */
; 	    if(*s++ == (BYTE) 0x1A)		/* looking for a Control-Z */
; 	        break;
; 	    i--;
; 	}
; 
; 	return (count - i);
; }

PUBLIC	_findeof
_findeof:
	push	bp			; establish a stack frame
	mov	bp,sp			;  s	dword 04[bp]
	push	es			;  count word 08[bp]
	push	di			; save important registers
	cld
	les	di,4[bp]		; load up the pointer
	mov	cx,8[bp]		;  and the count
	mov	al,26			; looking for EOF mark in the buffer
	repne	scasb			;  scan until we find one
	 jne	findeof10		; if we do find one
	inc	cx			;  then include it in the count
findeof10:
	mov	ax,8[bp]		; we wanted this many
	sub	ax,cx			;  subtract any past EOF
	pop	di
	pop	es
	pop	bp
	ret


ifdef	DLS
public	_my_dls_init
;	void my_dls_init()

	;extrn	_dls_init:near
	;extrn	_dls_get_table:near

_my_dls_init proc far

	push	ds

	push	cs
	pop	ds
	
	call	_dls_init
	mov	ax,1
	push	ax
	call	_dls_get_table
	pop	ax

	pop	ds
	ret

_my_dls_init endp

public	_copy_crit_msgs
_copy_crit_msgs proc near 

	extrn	_crit_msgs:word
	extrn	_crit_text:byte

	push	ds
	push	es
	push	di
	push	si

	push	ds
	pop	es
	push	cs
	pop	ds

	mov	si,_dls_table
	add	si,msg0
	mov	si,[si]

	mov	di,offset DGROUP:_crit_text
	add	di,2
	mov	bx,offset DGROUP:_crit_msgs
	add	bx,2

	mov	cx,24
ccm_loop1:
	mov	es:[bx],di
	add	bx,2
ccm_loop2:
	lodsb
	stosb
	cmp	al,'$'
	jne	ccm_loop2
	loop	ccm_loop1

	pop	si
	pop	di
	pop	es
	pop	ds
	ret

_copy_crit_msgs endp

public	_copy_rld_msgs
_copy_rld_msgs proc near

	extrn	_rld_msgs:word
	extrn	_rld_text:byte

	push	ds
	push	es
	push	di
	push	si

	push	ds
	pop	es
	push	cs
	pop	ds

	mov	si,_dls_table
	add	si,reload_msgs
	mov	si,[si]

	mov	di,offset DGROUP:_rld_text
	add	di,2
	mov	bx,offset DGROUP:_rld_msgs
	add	bx,2

	mov	cx,3
crm_loop1:
	mov	es:[bx],di
	add	bx,2
crm_loop2:
	lodsb
	stosb
	cmp	al,0
	jne	crm_loop2
	loop	crm_loop1

	pop	si
	pop	di
	pop	es
	pop	ds
	ret

_copy_rld_msgs endp

public	_dls_msg1
;	char *dls_msg1(int)

_dls_msg1:
	push	bp
	mov	bp,sp
	push	bx

	mov	ax,4[bp]
	shl	ax,1
	mov	bx,cs:_dls_table	
	add	bx,ax
	mov	ax,cs:[bx]
		
	pop	bx
	pop	bp
	ret

endif   ; ifdef DLS

public	_dos_parse_filename
_dos_parse_filename	proc near

	push	bp
	mov	bp,sp
	sub	sp,30h
	push	es
	
	push	ds
	pop	es
	
	lea	di,-30h[bp]
	mov	si,4[bp]
	
	mov	ax,2901h
	int	21h
	
	mov	ah,0
	pop	es
	add	sp,30h
	pop	bp
	ret	

_dos_parse_filename	endp

public	_flush_cache
_flush_cache	proc near

	push	si
	push	di
	push	bp
	
	mov	ax,4a10h
	mov	bx,0
	mov	cx,0edch
	int	2fh
	
	cmp	ax,6756h	; NWCACHE
	je	do_flush
	cmp	ax,0BABEh	; SmartDrive
	jne	skip_flush

do_flush:
	mov	ax,4a10h
	mov	bx,1
	mov	cx,0edch
	int	2fh	
	
skip_flush:
	pop	bp
	pop	di
	pop	si
	ret



_flush_cache	endp


_TEXT	ENDS

	page
_DATA	SEGMENT	byte public 'DATA'
	extrn	__psp:word
	extrn	_end:byte
	extrn	_break_env:word
	extrn	low_seg:word

	public	stack_min
	public	heap_top
ifdef TURBOC
	public	___brklvl		; Turbo C does an inline check against
___brklvl	label	word		; ___brklvl and id SP < ___brklvl then
endif					; it calls OVERFLOW@
stack_min	dw	dataOFFSET _end + STACKSLOP
heap_top	dw	dataOFFSET _end	; Current Top of Heap

_DATA	ENDS
	END
