File:  [OS/2 SDKs] / os2sdk / startup / dos / crt0dat.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:25:13 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: os2sdk-1987, HEAD
Microsoft OS/2 SDK 12-15-1987

	page	,132
	TITLE	crt0dat - DOS and Windows shared startup and termination
;***
;crt0dat.asm - DOS and Windows shared startup and termination
;
;	Copyright (c) 1985-1987, Microsoft Corporation.  All rights reserved.
;
;Purpose:
;	Shared startup and termination.
;
;*******************************************************************************

_NFILE_	=	20		; Maximum number of file handles

?DF	=	1		;; tell cmacros.inc we want to define our own segments

include	version.inc
.xlist
ifdef	_QC			;[8] Move these includes out of version.inc
include	\sl\qc\src\include\kernel.inc	;[8]
include \sl\qc\src\include\kmac.inc	;[8]
endif	;_QC			;[8]

include	cmacros.inc
include	msdos.inc
.list

ifdef	_QC
BEGINT	equ	34h		;First EM.LIB interrupt vector.
NUMVEC	equ	11		;Uses 11 actual vectors.
endif	;_QC

createSeg _TEXT, code,	word,	public, CODE,	<>
createSeg CDATA, cdata,	word,	common, DATA,	DGROUP
createSeg _DATA, data,	word,	public, DATA,	DGROUP

ifndef	IBMC20
createSeg XIFB,	xifbseg, word,	public, DATA,	DGROUP
createSeg XIF,	xifseg,	word,	public, DATA,	DGROUP ; far init's
createSeg XIFE,	xifeseg, word,	public, DATA,	DGROUP
endif	;IBMC20

createSeg XIB,	xibseg, word,	public, DATA,	DGROUP
createSeg XI,	xiseg,	word,	public, DATA,	DGROUP ; init's
createSeg XIE,	xieseg, word,	public, DATA,	DGROUP

createSeg XOB,	xobseg, word,	public, BSS,	DGROUP
createSeg XO,	xoseg,	word,	public, BSS,	DGROUP ; onexit table
createSeg XOE,	xoeseg, word,	public, BSS,	DGROUP

createSeg XPB,	xpbseg, word,	public, DATA,	DGROUP
createSeg XP,	xpseg,	word,	public, DATA,	DGROUP ; preterm's
createSeg XPE,	xpeseg, word,	public, DATA,	DGROUP

createSeg XCB,	xcbseg, word,	public, DATA,	DGROUP
createSeg XC,	xcseg,	word,	public, DATA,	DGROUP ; term's
createSeg XCE,	xceseg, word,	public, DATA,	DGROUP

ifndef	IBMC20
createSeg XCFB,	xcfbseg, word,	public, DATA,	DGROUP
createSeg XCF,	xcfseg,	word,	public, DATA,	DGROUP ; far term's
createSeg XCFE,	xcfeseg, word,	public, DATA,	DGROUP
endif	;IBMC20

defGrp	DGROUP			;; define DGROUP

codeOFFSET equ	offset _TEXT:
dataOFFSET equ	offset DGROUP:

page
ifndef	IBMC20
sBegin	xifbseg
xifbegin label	byte
sEnd	xifbseg

sBegin	xifeseg
xifend	label	byte
sEnd	xifeseg
endif	;IBMC20

sBegin	xibseg
xibegin	label	byte
sEnd	xibseg

sBegin	xieseg
xiend	label	byte
sEnd	xieseg

sBegin	xobseg
xontab	label	byte		; start of onexit table
sEnd	xobseg

sBegin	xoeseg
xonend	label	byte
sEnd	xoeseg

sBegin	xpbseg
xpbegin	label	byte		; end of onexit table
sEnd	xpbseg

sBegin	xpeseg
xpend	label	byte
sEnd	xpeseg

sBegin	xcbseg
xcbegin	label	byte
sEnd	xcbseg

sBegin	xceseg
xcend	label	byte
sEnd	xceseg

ifndef	IBMC20
sBegin	xcfbseg
xcfbegin label	byte
sEnd	xifbseg

sBegin	xcfeseg
xcfend	label	byte
sEnd	xcfeseg
endif	;IBMC20

ifdef _QC
	extrn	$Exec_Shell:FAR
	extrn	$Terminate_QC:FAR	;[5] exit point for shell exits
	extrn	__fpsignal:FAR
	extrn	$EmulInit:FAR		;[6]
	extrn	$EmulTerm:FAR		;[6]
endif	;_QC

sBegin	cdata			; floating point setup segment
assumes	ds,data

	dw	0		; force segment to be at least 0's
labelD	<PUBLIC,_fpinit> 	; public for signal
fpmath	dd	1 dup (?)	; linking trick for fp
fpdata	dd	1 dup (?)
ifdef	_QC
fpsignal dd	__fpsignal	; fp signal message
else	;_QC
fpsignal dd	1 dup (?)	; fp signal message
endif	;_QC

ifdef	_QC			;[5]
staticB	shellexit,0		;[5] marker for special exit for shell
endif	;_QC			;[5]

sEnd

ifdef	_QC
externP	_Break_error
endif	;_QC

sBegin	data
assumes	ds,data

;	special C environment string

	labelB	<PUBLIC,_acfinfo>
	cfile	db	';C_FILE_INFO'
	cfilex	db	0
	cfileln	=	cfilex-cfile

ifdef	_QC
globalD		_abrkvec,0		;[4]break interrupt vector
endif	;_QC

globalD	_aintdiv,0 		; divide error interrupt vector save

globalQ	_fac,0			; floating accumulator
globalW	errno,0			; initial error code
globalW	_umaskval,0 		; initial umask value

;=============== following must be in this order

globalW	_pspadr,0 		; psp:0 (far * to PSP segment)
globalW	_psp,0			; psp:0 (paragraph #)

;=============== above must be in this order

;=============== following must be in this order

labelW	<PUBLIC,_osversion>
labelB	<PUBLIC,_dosvermajor>
globalB	_osmajor,0
labelB	<PUBLIC,_dosverminor>
globalB	_osminor,0

;=============== above must be in this order


globalB	_osmode,0 		; 0 = real mode

labelW	<PUBLIC,_oserr>
globalW	_doserrno,0 		; initial DOS error code

globalW	_nfile,_NFILE_ 		; maximum number of file handles

labelB	<PUBLIC,_osfile>
	db	3 dup (FOPEN+FTEXT) ; stdin, stdout, stderr
	db	2 dup (FOPEN)	; stdaux, stdprn
	db	_NFILE_-5 dup (0) ; the other 15 handles


globalW	__argc,0
globalDP __argv,0
globalDP environ,0 		; environment pointer

labelD	<PUBLIC,_pgmptr> 	; pointer to program name
	dw	dataOFFSET dos2nam,DGROUP
dos2nam	db	'C',0		; dummy argv[0] for DOS 2.X


; signal related common data

globalW	_child,0 		; flag used to handle signals from child process

ifndef	_QC			;[XX] we don't do overlays
ifndef	IBMC20
;Overlay related data

globalB _ovlflag,0	;Overlay flag (0 = no overlays)
globalB	_intno,0	;Overlay interrupt value (e.g., 3F)
globalD _ovlvec,0	;Address of original overlay handler
endif
endif	;_QC			;[XX] we don't do overlays

ifdef	 _QC
con	db	'CON',0
_fpsave	dd	NUMVEC dup (0)
endif	;_QC

ifdef _QC			;[1]
; DWORD pointer for runtime errors.  Routines calling amsg_exit set this
; to their 'best guess' for the CS:IP where the error occurred.  amsg_exit
; then uses this information to set up information for return to the shell.
; [1]

globalD	_QCrtcsip, 0	;[1]
endif	;_QC		;[1]

sEnd	data

page
sBegin	code
assumes	cs,code

if	sizeC
global	proc	far
endif

ifndef	_QC				;[X] fptrap has vanished
externNP _fptrap
endif	;_QC				;[X]
externP	_cintDIV
externP	_nullcheck

ifdef	_QC				;[10]
extrn	$F_PSP:WORD			;[10]
endif	;ifdef _QC			;[10]

page
;***
;_cinit - C initialization
;
;Purpose:
;	This routine performs the shared DOS and Windows initialization.
;	The following order of initialization must be preserved -
;
;	1.	Integer divide interrupt vector setup
;	2.	Floating point initialization
;	3.	Copy ;C_FILE_INFO into _osfile
;	4.	Check for devices for file handles 0 - 4
;	5.	General C initializer routines
;
;Entry:
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

cProc	_cinit,<PUBLIC>,<>

cBegin	nogen			; no local frame to set up
assumes	ds,data
assumes	ss,data

;	Store DOS major/minor version number
;	This is done in crt0dat.asm rather than in crt0.asm for Windows' sake.
;

	callos	VERSION
	mov	[_osversion],ax

;	1.	Integer divide interrupt vector setup

	mov	ax,DOS_getvector shl 8 + 0
	callos			; save divide error interrupt
	mov	word ptr [_aintdiv],bx
	mov	word ptr [_aintdiv+2],es

	push	cs
	pop	ds
	assumes	ds,nothing
	mov	ax,DOS_setvector shl 8 + 0
	mov	dx,codeOFFSET _cintDIV
	callos			; set divide error interrupt
	push	ss
	pop	ds
	assumes	ds,data


ifdef	_QC
;	1a. BREAK interrupt vector setup.

	INT21	3523h			;[4]Get vector via MSDOS.

	mov	Word Ptr [__abrkvec],bx	;[4]save vector offset
	mov	Word Ptr [__abrkvec+2],es ;[4]save vector segment

	push	cs			;[4]
	pop	ds			;[4]
	mov	es,$F_PSP		;[10]get QC PSP for flags
	test	es:[PSP_KERNEL_FLGS],PSP_KF_SHELL ;[10]test if in SHELL
	mov	dx,codeOFFSET intret	;[10]set DS:DX to int-return pointer
	JNZ	cinit_shell		;[10]if SHELL, then jump
	mov	dx,codeOFFSET __Break_error ;[4]
cinit_shell:				;[10]
	INT21	2523h			;[4]Set up new break vector

	push	ss			;[4]
	pop	ds			;[4]
endif	;_QC

;	2.	Floating point initialization

ifndef	_QC
	mov	cx,word ptr [fpmath+2]
	jcxz	nofloat_i

	mov	es,[_psp]	; psp segment
	mov	si,es:[DOS_ENVP] ; environment segment
	lds	ax,[fpdata]	; get task data area
	assumes	ds,nothing
	mov	dx,ds		;   into dx:ax
	xor	bx,bx		; (si) = environment segment
	call	[fpmath]	; fpmath(0) - init
	jnc	fpok

	push	ss		; restore ds from ss
	pop	ds
	jmp	_fptrap		; issue "Floating point not loaded"
				; error and abort

fpok:
	lds	ax,[fpsignal]	; get signal address
	assumes	ds,nothing
	mov	dx,ds
	mov	bx,3
	call	[fpmath]	; fpmath(3) - set signal address
	push	ss
	pop	ds
	assumes	ds,data

nofloat_i:
else	;_QC
;	cCall	$EmulInit,<addr of __fpinit>	;[9]
	push	ds				;[9]
	mov	ax,dataOffset _fpinit		;[9]
	push	ax				;[9]
	call	$EmulInit			;[6]
endif	;_QC

;	3.	Copy ;C_FILE_INFO into _osfile

;	fix up files inherited from child using ;C_FILE_INFO

	mov	es,[_psp]	; es = PSP
	mov	cx,word ptr es:[DOS_envp] ; es = user's environment
	jcxz	nocfi		;   no environment !!!
	mov	es,cx
	xor	di,di		; start at 0

cfilp:
	cmp	byte ptr es:[di],0 ; check for end of environment
	je	nocfi		;   yes - not found
	mov	cx,cfileln
	mov	si,dataOFFSET cfile
	repe	cmpsb		; compare for ';C_FILE_INFO'
	je	gotcfi		;   yes - now do something with it
	mov	cx,07FFFh	; environment max = 32K
	xor	ax,ax
	repne	scasb		; search for end of current string
	jne	nocfi		;   no 00 !!! - assume end of env.
	jmp	cfilp		; keep searching

;	found ;C_FILE_INFO and transfer info into _osfile

gotcfi:
	push	es
	push	ds
	pop	es		; es = DGROUP
	pop	ds		; ds = env. segment
	assumes	ds,nothing
	assumes	es,data
	mov	si,di		; si = startup of _osfile info
	mov	di,dataOFFSET _osfile ; di = _osfile block

	lodsb			; must be less than 20
	cbw
	xchg	cx,ax		; cx = number of entries

osflp:
	lodsb			; get next byte
	inc	al
	jz	saveit		; was FF - save as 00
	dec	ax		; restore al
saveit:
	stosb
	loop	osflp		; transfer next character

	push	ss
	pop	ds		; ds = DGROUP
	assumes ds,data
nocfi:


;	4.	Check for devices for file handles 0 - 4
;
;		Clear the FDEV bit (which might be inherited from C_FILE_INFO)
;		and then call DOS to see if it really is a device or not
;
	mov	bx,4

devloop:
	and	_osfile[bx],not FDEV ; clear FDEV bit on principal

	mov	ax,DOS_ioctl shl 8 + 0 ; issue ioctl(0) to get dev info
	callos
	jc	notdev

	test	dl,80h		; is it a device ?
	jz	notdev		;   no
	or	_osfile[bx],FDEV ;   yes - set FDEV bit

notdev:
	dec	bx
	jns	devloop

;	5.	General C initializer routines

ifndef	IBMC20
	mov	si,dataOFFSET xifbegin
	mov	di,dataOFFSET xifend
if	sizeC
	call	initterm	; call the far initializers
else
	call	farinitterm	; call the far initializers
endif

ifdef	 _QC					;[2]
	mov	bx,24				;[2] offset in table
	mov	si,PSP_UL_TERM_OFF		;[7] QLB initializers
	call	ulibinitterm			;[2] execute far C initializers

	mov	bx,24				;[7] offset in table
	mov	si,PSP_EXE_TRM_OFF		;[7] .exe initializers
	call	ulibinitterm			;[7] execute far C initializers
endif	;_QC					;[2]
endif	;IBMC20

	mov	si,dataOFFSET xibegin
	mov	di,dataOFFSET xiend
	call	initterm	; call the initializers

ifdef _QC					;[2]
	mov	bx,0				;[2] offset in table
 	mov	si,PSP_UL_TERM_OFF		;[7] User Lib initializers
	call	ulibinitterm			;[2] execute C initializers

	mov	bx,0				;[7] offset in table
	mov	si,PSP_EXE_TRM_OFF		;[7] .exe initializers
	call	ulibinitterm			;[7] execute far C initializers
endif	;_QC					;[2]

	ret
cEnd	nogen

page
;***
;exit(status), _exit(status) - C termination
;
;Purpose:
;	The termination sequence is more complicated due to the multiple
;	entry points - exit(code) and _exit(code).  The _exit() routine
;	is a quick exit routine that does not do certain C exit functions
;	like stdio buffer flushing and onexit processing.
;
;	exit (status):
;
;	1.	call runtime preterminators
;
;	_exit (status):
;
;	2.	perform C terminators
;	3.	perform _nullcheck() for null pointer assignment
;	4.	close all open files
;	5.	terminate floating point
;	6.	reset divide by zero interrupt vector
;	7.	restore int 3F handler
;	8.	terminate with return code to DOS
;
;Entry:
;	int status - exit status
;
;Exit:
;	returns to DOS.
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

public	_exit
_exit:
cProc	dummy1,<>,<>

parmw	status

cBegin
assumes	ds,data
assumes	ss,data

;	1.	call runtime preterminators
;		- onexit processing
;		- flushall
;		- rmtmp

	mov	si,dataOFFSET xontab ; beginning of onexit table
	mov	di,dataOFFSET xonend ; end of onexit table
	call	initterm

	mov	si,dataOFFSET xpbegin ; beginning of pre-terminators
	mov	di,dataOFFSET xpend ; end of pre-terminators
	call	initterm

ifdef	_QC				;[2]
	; [2] call the preterminators for the user library.

	mov	bx,8				;[2] offset in table
	mov	si,PSP_UL_TERM_OFF		;[7] User Lib initializers
	call	ulibinitterm			;[2] execute C terminators

	mov	bx,8				;[7] offset in table
	mov	si,PSP_EXE_TRM_OFF		;[7] .exe initializers
	call	ulibinitterm			;[7] execute far C initializers
endif	;_QC					;[2]	

	jmp	short exiting	; jump into _exit

cend	nogen

ifdef	_QC				;[5]

public	__shell_exit			;[5]
__shell_exit:				;[5]

cProc	dummy3,<>,<>			;[5]
parmw	status				;[5]	

cBegin					;[5]
	mov	[shellexit],1		;[5] mark as a shell exit
	jmp	short exiting		;[5] jump into _exit
cEnd	nogen				;[5]

public	__qcexit			;[11]
__qcexit:				;[11]

cproc	dummy4,<>,<>			;[11]
parmw	status				;[11]

cBegin					;[11]
	jmp	short	startclose	;[11]
cEnd	nogen				;[11]
endif	;_QC				;[5]

public	__exit
__exit:
cProc	dummy2,<>,<>

parmw	status

cBegin
assumes	ds,data
assumes	ss,data

exiting:

;	2.	perform C terminators

	mov	si,dataOFFSET xcbegin
	mov	di,dataOFFSET xcend
	call	initterm	; call the terminators

ifdef	_QC				;[2]
	; [2] call the terminators for the user library.

	mov	bx,16				;[2] offset in table
	mov	si,PSP_UL_TERM_OFF		;[7] User Lib initializers
	call	ulibinitterm			;[2] execute C terminators

	mov	bx,16				;[7] offset in table
	mov	si,PSP_EXE_TRM_OFF		;[7] .exe initializers
	call	ulibinitterm			;[7] execute far C initializers
endif	;_QC					;[2]

ifndef	IBMC20
	mov	si,dataOFFSET xcfbegin
	mov	di,dataOFFSET xcfend
if	sizeC
	call	initterm	; call the far terminators
else
	call	farinitterm	; call the far terminators
endif

ifdef	_QC				;[2]
	; [2] call the terminators for the user library.

	mov	bx,32				;[2] offset in table
	mov	si,PSP_UL_TERM_OFF		;[7] User Lib initializers
	call	ulibinitterm			;[2] execute far terminators

	mov	bx,32				;[7] offset in table
	mov	si,PSP_EXE_TRM_OFF		;[7] .exe initializers
	call	ulibinitterm			;[7] execute far C initializers
endif	;_QC					;[2]

endif	;IBMC20

;	3.	perform _nullcheck() for null pointer assignment

	call	_nullcheck	; check data in NULL data segment at DS:0
	or	ax,ax		; zero if no null ptr assignment detected
	jz	startclose
	cmp	status,0	; zero if no other error has occurred
	jnz	startclose
	mov	status,255	; nonzero status to indicate an
				; null-pointer-assignment error
startclose:

;	4.	close all files (except pre-opened handles 0-4)

ifdef	_QC

;
; M00BUG -- Can't assume that devices 0, 1, 2, 3, and 4 are DEVICE only.
;

	mov	cx,_NFILE						;[ 1]
	xor	bx,bx							;[ 1]
									;[ 1]
closeloop:								;[ 1]
	cmp	bx,5							;[ 1]
	jae	closeit			;Unless > 4, which must close.	;[ 1]
									;[ 1]
	test	[__osfile+bx],FDEV					;[ 1]
	jz	openit	 		;Must open devices 0 -> 4.	;[ 1]
									;[ 1]
	test	[__osfile+bx],FOPEN					;[ 1]
	jnz	cycle_files		;DEVICE's should stay open.	;[ 1]
									;[ 1]
openit:									;[ 1]
	mov	dx,dataOFFSET con	;Ugly brute force method.	;[ 1]
	mov	ax,3D02h						;[ 1]
	int	21h							;[ 1]
									;[ 1]
	jmp	short cycle_files					;[ 1]
									;[ 1]
closeit:								;[ 1]
	test	[__osfile+bx],FOPEN					;[ 1]
	jz	cycle_files						;[ 1]
									;[ 1]
	INT21	3Eh			;MSDOS close file.		;[ 1]
									;[ 1]
cycle_files:								;[ 1]
	inc	bx
	loop	closeloop

else	;_QC
	mov	cx,_NFILE_-5
	mov	bx,5		; close handles that are not pre-opened

closeloop:
	test	_osfile[bx],FOPEN
	jz	notopen

	callos	close

notopen:
	inc	bx
	loop	closeloop
endif	;_QC

;	5.	terminate floating point
;	6.	reset divide by zero interrupt vector
;	7.	restore int 3F handler

	call	_ctermsub	; fast cleanup

ifdef	 _QC
;	8.	return to SHELL.

	cmp	[shellexit],1
	je	exit_sh1

	mov	ax,[status]
	jmp	Far Ptr $Exec_Shell

exit_sh1:
	mov	ax,[status]
	jmp	Far Ptr $Terminate_QC

;[10]	Interrupt return for control-break routine while in SHELL.

intret:				;[10]
	IRET			;[10]immediate return while in termination

else	;_QC
;	8.	return to the DOS

	mov	ax,status	; get return value
	callos	terminate	; exit with al = return code
endif	;_QC

cEnd	nogen

if	sizeC
global	endp
endif

page
;***
;_ctermsub - more C termination code
;
;Purpose:
;	This routine 
;		(1) performs floating-point termination
;		(2) resets the divide by zero interrupt vector
;		(3) restore int 3F handler
;
;Entry:
;
;Exit:
;
;Uses:
;	AX,BX,CX,DX.
;
;Exceptions:
;
;*******************************************************************************

labelNP	<PUBLIC,_ctermsub>

;	5.	terminate floating point
ifndef	_QC
	mov	cx,word ptr [fpmath+2] ; test for floating point
	jcxz	nofloat_t	;   no

	mov	bx,2		;   yes - cleanup
	call	[fpmath]

nofloat_t:
else	;_QC			;[6]
	call	$EmulTerm	;[6] clean up floating point
endif	;_QC			;[6]

;	6.	reset divide by zero interrupt vector

	push	ds
	lds	dx,[_aintdiv]	; ds:dx = restore vector
	mov	ax,DOS_setvector shl 8 + 0
	callos			; set divide error interrupt
	pop	ds

ifdef	_QC
;	6a.	reset Control break interrupt vector

	push	ds			;[4]
	lds	dx,[__abrkvec]		;[4]Original BREAK vector.
	INT21	2523h			;[4]
	pop	ds			;[4]
endif	;_QC

ifndef	_QC				;[XX]  We don't have overlays
ifndef	IBMC20
;	7.	restore overlay interrupt vector
	
	cmp	byte ptr [_ovlflag],0	; Overlays in use ??
	jz	done_ovlvec		; if 0, don't restore overlay vector
	push	ds			; save ds
	mov	al,byte ptr [_intno]	; overlay interrupt number
	lds	dx,dword ptr [_ovlvec]	; original ovl interrupt vector
	callos	setvector		; restore the overlay vector
	pop	ds			; restore ds
done_ovlvec:
endif
endif	; _QC				;[XX]
	ret


page
;***
;initterm - do a set of initializers or terminators
;
;Purpose:
;	The initializors and terminators may be written in C
;	so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
;	We go through them in reverse order for onexit.
;
;Entry:
;	SI	= start of procedure list
;	DI	= end of procedure list
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

initterm:
	cmp	si,di		; are we done?
	jae	itdone		;   yes - no more

if	sizeC
	sub	di,4
	mov	ax,[di]
	or	ax,[di+2]
	jz	initterm	; skip null procedures
	call	dword ptr [di]
else
	dec	di
	dec	di
	mov	cx,[di]
	jcxz	initterm	; skip null procedures
	call	cx
endif
	jmp	initterm	; keep looping

itdone:
	ret

page
ifndef	IBMC20
ife	sizeC			; S/C models only
;***
;farinitterm - do a set of far initializers or terminators
;
;Purpose:
;	The initializors and terminators may be written in C
;	so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
;	We go through them in reverse order for onexit.
;
;Entry:
;	SI	= start of procedure list
;	DI	= end of procedure list
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

farinitterm:
	cmp	si,di		; are we done?
	jae	faritdone	;   yes - no more

	sub	di,4
	mov	ax,[di]
	or	ax,[di+2]
	jz	farinitterm	; skip null procedures
	call	dword ptr [di]
	jmp	farinitterm	; keep looping

faritdone:
	ret
endif	;sizeC
endif	;IBMC20
	

ifdef	_QC				;[2]
;***
; ulibinitterm - do a set of far initializers or terminators
;
;Purpose:
;	The initializors and terminators may be written in C
;	so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
;	We go through them in reverse order for onexit.
;
;Entry:
;	BX = Offset in User Library Init table to use
;
;Exit:
;
;Uses:
;	SI, DI, CX, AX, ES
;
;Exceptions:
;
;*******************************************************************************

ulibinitterm:					;[2]
	push	ds				;[2] save DGROUP
	cmp	[shellexit],1			;[7]
	je	skipfarterm			;[7] shell does not do this initializations

	mov	ds,[_psp]			;[2] get pointer to PSP
	lds	si,dword ptr ds:[si]		;[7] load user library far terminator table address
	mov	cx,ds				;[2] verify that the table exists
	or	cx,si				;[2]
	jz	skipfarterm			;[2] NO? then skip over initialization code
	les	di,ds:[si+bx]+4			;[2] Get end of far terminator list
						;[2] Compute offset of list from DGROUP
	mov	ax,es				;[2]	ax = list segment
	pop	cx				;[2]	cx = DGROUP segment
	push	cx				;[2]
	sub	ax,cx				;[2]	difference
	mov	cl,4				;[2]
	shl	ax,cl				;[2]	shift up
	add	di,ax				;[2]
	les	si,ds:[si+bx]			;[2] Get end of far terminator list
						;[2] Compute offset of list from DGROUP
	mov	ax,es				;[2]	ax = list segment
	pop	cx				;[2]	cx = DGROUP segment
	push	cx				;[2]
	sub	ax,cx				;[2]	difference
	mov	cl,4				;[2]
	shl	ax,cl				;[2]	shift up
	add	si,ax				;[2]
	pop	ds				;[2] Restore DGROUP
	push	ds				;[2]
	call	initterm			;[2] Execute the list of far terminators

skipfarterm:					;[2]
	pop	ds				;[2] restore dgroup
	ret					;[2]
endif	;_QC					;[2]

sEnd
	end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.