;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%  Copyright (C) 1988-1994 by WATCOM International Corp. All	%
;%  rights reserved. No part of this software may be reproduced %
;%  in any form or by any means - graphic, electronic or	%
;%  mechanical, including photocopying, recording, taping	%
;%  or information storage and retrieval systems - except	%
;%  with the written permission of WATCOM International Corp.	%
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%								   %
;%	 This module was modified for use with AutoCAD's protect   %
;%	 mode ADI and ADS.  AutoCAD is a registered trademark of   %
;%	 Autodesk, Inc.						   %
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;
; startup code for WATCOM C/C++32 Version 10.0
;
;	This must be assembled using one of the following commands:
;		wasm adstart -fo=adsstart.obj -dADS -3s_
;		wasm adstart -fo=adifstrt.obj -dPADI -3s_
;		wasm adstart -fo=adiestrt.obj -dPADI -dEADI -3s_
;
	name	adsstart

.387
.386p

comment @
	Modified for AutoLISP and protect mode ADI

	Expects to be called at starting address as a subroutine, rather
	than as an executable program from the operating system.  Stack
	and segment registers must be correctly set up; and some
	additional information is expected in these registers:

	ECX	Compatibility-check value.  Must be equal to (our
		locally defined symbol) chkval.	 If it isn't, we assume
		we are erroneously being executed as an independent
		separate program.  This won't work, so we exit
		immediately to the system.

	DS:ESI	Pointer to structure containing initialization information.
		A minimum structure size of 8 bytes is mandatory (12 bytes
		if PADI is set).  The first 4 bytes of the structure must
		contain the number of bytes making up the structure.  The
		second 4 bytes must contain the initial heapsize of the
		child process, obtained from the loader in AutoCAD.  If
		PADI is set, the third 4 bytes must contain the physical
		address of the packet buffer in AutoCAD to be used for
		communication with protect mode ADI drivers.  All subsequent
		bytes are the business between AutoCAD and the loaded child
		process and may vary.

	The value we return is the argument to exit() which terminates us.
	We preserve no registers, not even SS and SP.

	Some protected mode ADI, ADS, and AutoLISP modifications are
	conditioned on the tag ACAD.

	Some code for ADS only is included only if the tag ADS is
	predefined (e.g., in the assembler command line).

	Code required for AutoCAD protected mode ADI drivers only is included
	by setting PADI in the assembler command line.
	@

ACAD   equ  1	; Protect mode ADI and AutoLISP version of module.
minmem equ  4	; Offset within the structure containing initialization
		; information to the inital heap size of the child process.
ifdef	PADI
physadr equ 8	; Offset within the structure containing initialization
		; information to the physical address of a buffer shared
		; between AutoCAD and a protect mode ADI driver.
endif	; PADI


	assume	nothing

	extrn	__CMain		: near
	extrn	__InitRtns	: near
	extrn	__FiniRtns	: near
	extrn	__DOSseg__	: near

if	ACAD
ifdef	ADS
getinitinfo	=    adsi_getinitinfo
map_phys_mem	=    ads_map_phys_mem
endif	; ADS
ifndef	PADI
	extrn	getinitinfo	: near		; initialize child process
						; loaded by AutoCAD
endif	; !PADI
;
; map_phys_mem allows a 3rd party to install a routine to map physical
; memory between the stack and heap
;
extrn	map_phys_mem		: near
endif	; ACAD

	extrn	_edata		: byte		; end of DATA (start of BSS)
	extrn	_end		: byte		; end of BSS (start of STACK)

	extrn	_dynend		: dword
	extrn	_curbrk		: dword
	extrn	_psp		: word
	extrn	_osmajor	: byte
	extrn	_osminor	: byte
	extrn	_STACKLOW	: dword
	extrn	_STACKTOP	: dword
	extrn	_child		: dword
	extrn  __no87		: word
	extrn	_Extender	: byte
	extrn	_ExtenderSubtype: byte
	extrn	_Envptr		: dword
	extrn	_Envseg		: word
	extrn	__FPE_handler	: dword
	extrn  ___FPE_handler	: dword
	extrn	_LpCmdLine	: dword
	extrn	_LpPgmName	: dword

DGROUP group _NULL,_AFTERNULL,CONST,_DATA,DATA,XIB,XI,XIE,YIB,YI,YIE,_BSS,STACK

; this guarantees that no function pointer will equal NULL
; (WLINK will keep segment 'BEGTEXT' in front)

BEGTEXT	 segment use32 word public 'CODE'
	assume	cs:BEGTEXT
___begtext label byte
forever label	near
	int	3h
	jmp    short forever
	public ___begtext
	assume	cs:nothing
BEGTEXT	 ends

_TEXT	segment use32 word public 'CODE'

	assume	ds:DGROUP

_NULL	segment para public 'BEGDATA'
__nullarea label word
	db	01h,01h,01h,00h
	public	__nullarea
_NULL	ends

_AFTERNULL segment word public 'BEGDATA'
_AFTERNULL ends

CONST	segment word public 'DATA'
CONST	ends

XIB	segment word public 'DATA'
XIB	ends
XI	segment word public 'DATA'
XI	ends
XIE	segment word public 'DATA'
XIE	ends

YIB	segment word public 'DATA'
YIB	ends
YI	segment word public 'DATA'
YI	ends
YIE	segment word public 'DATA'
YIE	ends


_DATA	segment dword public 'DATA'

__x386_zero_base_selector dw 0	; base 0 selector for X-32VM
	public	__x386_zero_base_selector
if	ACAD
chkval	equ	1234		; magic interface-compatibility code
ifndef	ADS			; Avoid excess globals for ADS
	public	 brkflg, stkflg
	public	 info_off, info_sel
endif	; ADS
	public	__fsavcw
ifdef	PADI
	public	cbufadr
	align 4
cbufadr	 dd	0		; ptr to common pg between ACAD and PADI
phys_adr  dd	0		; physical address of common page
endif	; PADI
brkflg	 dd	0		; set nonzero for Control C
stkflg	 dd	0		; set nonzero for stack overflow
info_off dd	0		; Offset of initialization info struct
info_sel dw	0		; Selector of initialization info struct
rtnaddr	  df	0		; Caller's return address.
min_mem	  dd	0		; inital driver heap size
sav_ds	  dw	0
my_ds	  dw	0
__fsavcw  dw	0		; for saving AutoLISP's floating point cntl word
interr	  db	"Incompatible program interface",0Dh,0Ah,"$"
endif	; ACAD

_DATA	ends

DATA	segment word public 'DATA'
DATA	ends

_BSS	      segment word public 'BSS'
_BSS	      ends

if	ACAD
STACK_SIZE	equ	4000h
else
STACK_SIZE	equ	1000h
endif	; ACAD

STACK	segment para stack 'STACK'
stk	label	word
	db	(STACK_SIZE) dup(?)
STACK	ends


	assume	nothing
	public	_cstart_
	public	 __exit

	assume	cs:_TEXT

_cstart_ proc near
	jmp	short around

;
; copyright message
;
        db      "WATCOM C/C++32 Run-Time system. "
        db      "(c) Copyright by WATCOM International Corp. 1988-1994."
	db	" All rights reserved."
;
; miscellaneous code-segment messages
;
ConsoleName	db	"con",00h

	dd	___begtext	; make sure dead code elimination
				; doesn't kill BEGTEXT

around: sti				; enable interrupts

	assume	ds:DGROUP

PSP_SEG equ	24h
ENV_SEG equ	2ch

if	ACAD
	; Save AutoLISP's floating point control word, to be restored by
	; adsi_farcl() before returning to AutoLISP
ifndef	EADI
	fnstcw	__fsavcw
endif

	cmp	ecx,chkval		; Proper chkval argument?
	je	m00
	mov	edx,offset interr	; "Incompatible program interface"
	mov	ah,9
	int	21h			; Print message.
	mov	ax,4C01h
	int	21h			; Exit to DOS.
m00:
	mov	info_off,esi		; offset of initialization info struct
	mov	info_sel,dx		; selector of info struct
	mov	es,dx
	mov	eax,es:[esi].minmem
	mov	min_mem,eax		; initial heap size of driver
ifdef	PADI
	mov	eax,es:[esi].physadr
	mov	phys_adr,eax		; phys addr of pg w/ PADI packet buffer
endif	; PADI
	mov	ax,ds
	mov	es,ax
	pop	dword ptr rtnaddr	; Save return address, offset
	pop	ax
	mov	word ptr rtnaddr+4,ax	;    and segment.
	mov	my_ds,ds		; Save DS for use in __GETDS()
endif	; ACAD

	mov	ax,PSP_SEG		; get segment address of PSP
	mov	 _psp,ax		; save segment address of PSP
	mov	es,ax			; point to PSP
	and	esp,0fffffffch		; make sure stack is on a 4 byte bdry
	mov	ebx,esp			; get sp
	mov	 _STACKTOP,ebx		; set stack top
	mov	 _curbrk,ebx		; set first available memory location
;
;	get DOS & Extender version number
;
	;mov	ebx,'PHAR'		; set ebx to "PHAR"
	mov     ebx,50484152h		; set ebx to "PHAR"
	sub	eax,eax			; set eax to 0
	mov	ah,30h
	int	21h			; modifies eax,ebx,ecx,edx
	mov	_osmajor,al
	mov	_osminor,ah
	mov	ecx,eax			; remember DOS version number
	shr	eax,16			; get top 16 bits of eax
	cmp	ax,'DX'			; if top 16 bits = "DX"
	sete	al			; then its Pharlap
	jne	not_pharlap		; if its pharlap
	sub	bl,'0'			; - save major version number
	mov	al,bl			; - (was in ascii)
	mov	ah,0			; - subtype
	mov	bx,14h			; - get value of Phar Lap data segment
	jmp	short know_extender	; else
not_pharlap:				; - see if Rational DOS/4G
	mov	dx,78h			; - ...
	mov	ax,0FF00h		; - ...
	int	21h			; - ...
	mov	bx,17h			; - get writeable code segment for Ergo
	cmp	al,0			; - ...
	je	short know_extender	; - quit if not Rational DOS/4G
	mov	al,1			; - indicate Rational 32-bit Extender
	mov	ah,0			; - assume zero base subtype
	mov	bx,ds			; - just use ds (FLAT model)
	mov	 _psp,es		; - save segment address of PSP
;
know_extender:				; endif
	mov	_Extender,al		; record extender type
	mov	_ExtenderSubtype,ah	; record extender subtype
;;	mov	es,bx			; get access to code segment
;;	mov	es:__saved_DS,ds	; save DS value

;
;	copy command line into bottom of stack
;
	mov	es, _psp		; point to PSP
	mov	edx,offset DGROUP:_end
	add	edx,0FH
	and	edx,0FFFFFFF0H
	mov	edi,81H			; DOS command buffer es:edi
	sub	ecx,ecx
	mov	cl,es:[edi-1]		; get length of command
	cld				; set direction forward
	mov	al,' '
	rep	scasb
	lea	esi,-1[edi]
	mov	edi,edx
	mov	bx,es
	mov	dx,ds
	mov	ds,bx
	mov	es,dx			; es:edi is destination
	je	noparm
	inc	ecx
	rep	movsb
noparm: sub	al,al
	stosb				; store NULLCHAR
	mov	al,0			; assume no pgm name
	stosb				; . . .
	dec	edi			; back up pointer 1
	push	edi			; save pointer to pgm name
	mov	ds,dx			; restore ds
	push	ds			; save ds

	cmp	byte ptr  _Extender,1	; if OS/386 or Rational
	jg	short pharlap		; then
	  mov	dx,PSP_SEG		; - get PSP segment descriptor
	  mov	ds,dx			; - ... into ds
	  mov	dx,ds:[02ch]		; - get environment segment into dx
	  jmp	short haveenv		; else
pharlap:mov   dx,ENV_SEG		; - PharLap environment segment
haveenv:				; endif
	mov	es: _Envseg,dx		; save segment of environment area
	mov	ds,dx			; get segment addr of environment area
	sub	ebp,ebp			; assume "no87" env. var. not present
	sub	esi,esi			; offset 0
	mov	es: _Envptr,esi		; save offset of environment area
L1:	mov	eax,[esi]		; get first 4 characters
	or	eax,20202020h		; map to lower case
	;cmp	eax,'78on'		; check for "no87"
	cmp     eax,37386f6eh		; check for "no87"
	jne	short L2		; skip if not "no87"
	cmp	byte ptr 4[esi],'='	; make sure next char is "="
	jne	short L2		; no
	inc	ebp			; - indicate "no87" was present
L2:	cmp	byte ptr [esi],0	; end of string ?
	lodsb
	jne	L2			; until end of string
	cmp	byte ptr [esi],0	; end of all strings ?
	jne	L1			; if not, then skip next string
	lodsb
	inc	esi			; point to program name
	inc	esi			; . . .
;
;	copy the program name into bottom of stack
;
L3:	cmp	byte ptr [esi],0	; end of pgm name ?
	movsb				; copy a byte
	jne	L3			; until end of pgm name
	pop	ds			; restore ds
	pop	esi			; restore address of pgm name
	mov	ebx,esp			; end of stack in data segment


	assume	ds:DGROUP
if	ACAD
 ifdef	 EADI
	mov	bp,1			; force "no87" env. var as present
 endif
endif	; ACAD
	mov	__no87,bp		; set state of "no87" environment var

	mov	 _STACKLOW,edi		; save low address of stack

if	ACAD

ifdef	PADI
	add	ebx,4095		; round top of stack up a page
	shr	ebx,12			; get number of pages
	push	ebx			; store for later use
	push	ds
	pop	es
	mov	ah,4Ah			; set PADI memory size to smallest #
	int	21h			;   of pages ecompassing top of stack

	mov	ebx,phys_adr		; get phys addr of pg w/ packet buffer
	mov	eax,250Ah
	mov	ecx,1
	int	21h			; map pg w/ pkt buf to end of new PADI
					;   memory block, above top of stack
	mov	cbufadr,eax		; store mapped offset as ptr to buf

	call	map_phys_mem		; allow 3rd party a chance to map in
					;   phys mem (returns # of pgs mapped)
	pop	ebx			; get # of pgs to top of stack
	inc	ebx			; add 1 for page mapped to end of seg
	add	ebx,eax			; add add'l pgs mapped by 3rd party
	shl	ebx,12			; get bottom of heap, in bytes
	mov	_dynend,ebx		; set top of dynamic memory area
	mov	_curbrk,ebx		; set bottom of dynamic memory area
else	; PADI
	add	ebx,4095		; round it up a page
	shr	ebx,12			; get number of pages
	push	ebx			; store for later use
	push	ds
	pop	es
	mov	ah,4Ah			; set memory size to smallest #
	int	21h			;   of pages encompassing top of stack

	call	map_phys_mem		; allow 3rd party a chance to map in
					;   phys mem (returns # of pgs mapped)
	pop	ebx			; Get # of pgs to top of stack
	add	ebx,eax			; If so, add it in
	shl	ebx,12			; Get bottom of heap, in bytes
	mov	_curbrk,ebx		; set bottom of dynamic memory area
	mov	_dynend,ebx		; set top of dynamic memory area
endif	; PADI
	;mov	????,min_mem		; initial size of heap
else	; ACAD
	mov	 _dynend,ebx		; set top of dynamic memory area
endif	; ACAD

	mov	ecx,offset DGROUP:_end	; end of _BSS segment (start of STACK)
	mov	edi,offset DGROUP:_edata; start of _BSS segment
	sub	ecx,edi			; calc # of bytes in _BSS segment
	mov	dl,cl			; save bottom 2 bits of count in edx
	shr	ecx,2			; calc # of dwords
	sub	eax,eax			; zero the _BSS segment
	rep	stosd			; ...
	mov	cl,dl			; get bottom 2 bits of count
	and	cl,3			; ...
	rep	stosb			; ...

	mov	eax,offset DGROUP:_end	; cmd buffer pointed at by EAX
	add	eax,0FH
	and	al,0F0H
	mov	 _LpCmdLine,eax		; save command line address
	mov	 _LpPgmName,esi		; save program name address
	mov	eax,0FFh		; run all initalizers
	call	__InitRtns		; call initializer routines

if	ACAD
ifndef	PADI
Comment @
	Take information from a structure in AutoCAD, pointed to by
	info_sel:info_off, and store it for use by routines in the
	program loaded by AutoCAD to which this module is linked.
	@
	movzx	eax,word ptr info_sel
	push	eax
	push	info_off
	call	getinitinfo
	add	esp,8
endif
endif

ifdef ADS
	push	es
	mov	cl,3
	mov	ax,2502h
	int	21h
	jc	noi3
	mov	ax,es
	verr	ax
	jnz	noi3
	cmp	ebx,8
	jb	noi3
	sub	ebx,8
	mov	eax,es:[ebx]
	cmp	eax,'DIVW'
	jne	noi3
	mov	eax,es:4[ebx]
	cmp	eax,'!!OE'
	jne	noi3
	int	3
noi3:	pop	es
endif

	sub	ebp,ebp			; ebp=0 indicates end of ebp chain
	call	__CMain
_cstart_ endp


if	ACAD
comment @
	For applications which are called as a subroutine from AutoCAD
	(namely AutoLISP), here is the ultimate exit point which returns
	back to AutoCAD.
	@
ifdef	PADI
	public	 exit_to_acad
exit_to_acad:
	jmp   rtnaddr			; Return to AutoCAD
endif


;	Where we want attempted program exits to go:
ifdef	ADS
child_exit    equ    adsi_child_exit	 ; Adhere to ADS naming convention
endif
	      extrn  child_exit:near
endif	; ACAD


__exit	 proc near
 	pop	eax			; get return code
	jmp	short	ok

	public	 __do_exit_with_msg__

; input: ( char *msg, int rc ) always in registers

__do_exit_with_msg__:
 	push	edx			; save return code
	push	eax			; save msg
	mov	edx,offset ConsoleName
	mov	ax,03d01h		; write-only access to screen
	int	021h
	mov	bx,ax			; get file handle
	pop	edx			; get address of msg
	mov	esi,edx			; get address of msg
	cld				; make sure direction forward
L4:	lodsb				; get char
	cmp	al,0			; end of string?
	jne	L4			; no
	mov	ecx,esi			; calc length of string
	sub	ecx,edx			; . . .
	dec	ecx			; . . .
	mov	ah,040h			; write out the string
	int	021h			; . . .
	pop	eax			; get return code
ok:

	push	eax			; save return code
	mov	eax,00h			; run all finalizers
	mov	edx,0ffh		; run all finalizers
	call	__FiniRtns		; call finalizer routines
	pop	eax			; restore return code

if	ACAD
	jmp	child_exit		; do something more appropriate
else	; ACAD
	mov	ah,04cH			; DOS call to exit with return code
	int	021h			; back to DOS
endif	; ACAD

__exit	 endp


__null_FPE_rtn proc near
	ret				; return
__null_FPE_rtn endp

	public	__GETDS
__GETDS proc	near
public "C",___GETDSStart_
___GETDSStart_ label byte
	mov	ds,cs:my_ds		; load saved DS value
	ret
public "C",___GETDSEnd_
___GETDSEnd_ label byte
__GETDS endp

_TEXT	ends

	end	_cstart_
