small_m = 1
mach386 = 1
GOC = 1
comment %
This version of INIT.ASM is intended for High C/C++ version 3.1 only.
The heap initialization has been changed for compatibility with Phar Lap
TNT Dos Extender version 6.0 applications that use DLLs.
Starting in version 3.11 the initializer is largely in C, not assembly.
**************************************************************************
***  (c) Copyright 1983 - 1992            MetaWare Incorporated.       ***
**************************************************************************
***  You have the same rights to the object form of this program as    ***
***  you do to the object code of the library.  You may not distribute ***
***  this source, even if modified by you.                             ***
**************************************************************************
***  The source to this module is provided for the convenience of      ***
***  MetaWare Pascal and High C users that need to tailor their        ***
***  execution environments.  The casual user should NOT play with the ***
***  code. This code is subject to change without notice in future     ***
***  releases of the compilers.                                        ***
**************************************************************************
***  You must preserve the library copyright notice defined in this    ***
***  module if your program uses any portion at all of the run-time    ***
***  library (including this initializer or any other supplied run-    ***
***  time source).  The copyright notice is in the definition of       ***
***  the initial stack segment.  We recommend it be left right there.  ***
***  But you can move it to anywhere you want as long it appears in    ***
***  any linked program (.exe or ROM-burned program) using the library.***
**************************************************************************


      MetaWare Pascal or High C Runtime Initialization Module
                   for small model, protected mode 386.


 --------------------------------------------------------------------------
  This initializer supports:
 --------------------------------------------------------------------------
  a. Pharlap's 386 DOS|Extender, run386.
  b. A.I. Architect's (Eclipse) OS/386 DOS extender.

 --------------------------------------------------------------------------
  Assembly instructions:
 --------------------------------------------------------------------------
  By default, the code assumes the use of 386asm.  If your would like to
  use MASM, you must define USING_MASM later in the defines section.

 --------------------------------------------------------------------------
  Differences between Pascal and C run-time initialization:
 --------------------------------------------------------------------------
  In C, the argv array must be allocated and computed.  In Pascal argument
  processing is handled through a separate argument pacakge.

 --------------------------------------------------------------------------
  Defines that you can set:
 --------------------------------------------------------------------------
  1. USING_MASM.  Set this if you are using MASM to assemble this file.
  2. HC.  Set if this is for the High C library; not set otherwise.
  3. STACK_SIZE.  Set this to the size of the stack you want.
  4. no87.  Set this if you know you have no 8087 or 287.  It will eliminate
       the initialization code for the chip.
       Also, it will remove the printing of the "no87" environment variable
       if you have an 8087/287 and the no87 variable is set to non-blank string.
       (Don't confuse the "no87" define in this assembly from the no87
       MS-DOS environment variable.  Read the programmer's Guide for more info
       on the latter.)
       Another reason to set this variable is that you know you're never
       going to use an 8087/287, even if you have one.  It's especially
       useful to remove the printing of the no87 environment variable on
       programs for which the 8087/287 processor is irrelevant.
  5. DOS.   Set this if this initializer is for MS-DOS (default).  Unset it
       for embedded applications where DOS doesn't exist.  If you unset it,
       you won't get argc/argv for C, nor the arg package for Pascal.
       It doesn't remove all of the DOS-dependent code -- some of it you must
       still rewrite for embedded applications (like how to find the top of
       memory).  (By "unset" we mean just comment out the line setting it!)
       Note that unsetting DOS doesn't remove all DOS-dependent code in
       the library.  For example, the interrupt handler initialization
       uses INT 21h, and so does all I/O.  Read the Embedded Applications
       section of the Programmer's Guide for more information about how
       to change those modules (source is generally provided).
  6. SG_exists  -- Set when IGC environment is possible.
       Unsetting it comments out code dependent on that environment only.
  7. PL_exists  -- Set when PharLap DOS|Extender environment is possible.
       Unsetting it comments out code dependent on that environment only.
  8. NOWTK      -- Set if either the Weitek 1167 will never be present or
       if you never care about it.
  9. PHAR_LAP_CAN_GROW_HEAP. Phar Lap's DOS|Extender 1.1t or later can grow
       the heap dynamically. For enabling Phar Lap DOS|Extender to grow the
       heap dynamically, ; uncomment the next line.
 10. AIA_CAN_GROW_HEAP. For Lahey-linked programs, we assume expansion can
       occur, since such linked programs do not give you all of memory.

 --------------------------------------------------------------------------
  Initializer Source Files 
 --------------------------------------------------------------------------

 Set the appropriate defines in the init.inc module, and then assemble
 init.asm, init_67.asm, and init_87.asm.

 init.inc - This file includes definitions used across assembly files
 init.asm - general stuff	
 init_67.asm - Weitek coprocessor initialization
 init_87.asm - x87, Cyrix coprocessor initialization

 init.h	- Include file to access intializer globals, functions from C 
 cinit.c - Main initialization routine. Makes calls into init.asm code. 

 mini-Makefile:

	 INITOBJS = init.obj init_67.obj init_87.obj cinit.obj 
	
	 .asm.obj:
		386asm $@
	
	 .c.obj:
		hc386 -c $@
	
	 init.obj:	init.inc init.asm 
	
	 init_67.obj:	init.inc init_67.asm 
	
	 init_87.obj:	init.inc init_87.asm 

 	 cinit.obj:	init.h cinit.c

 --------------------------------------------------------------------------
  Memory Layout:
 --------------------------------------------------------------------------

 High memory   +---------------+
               | END OF MEMORY |
               |---------------|
  _heaphi ->   | top-of-heap   |
  _heaptop ->  |   ...         |
               | bottom-of-heap|
  _TOP  ->     |---------------|  <- Of size STACK_SIZE, unless there isn't
               |   stack       |  <- room, in which case the first heap
               |   ...         |  <- allocation will fail.
               | end-of-stack  |
  _BASE ->     +---------------+
               DATA   segments   (static variables and named common)
 Low memory    CODE   segments
 See the programmer's guide for more information and pictures of
 run-time organization with the different memory models.
 Stack margin1 is 512 bytes above the true end-of-stack.
 Stack margin2 is 256 bytes above the true end-of-stack.
 In non-large models, the stack margins go in a reserved area in the data
 segment, not in the stack segment.  In the large model, since there is
 no single data segment, the stack margins go at the tail end of the stack
 (at ss:-2 and ss:-4).

 If stack overflow checking is enabled, here is the code that is generated:
       For procedures using 256 or less bytes in the stack:
               cmp     esp,Stack_margin_1
               jnb     around
               int     0
       around: ...

       Since Stack_margin_2 is 512 above true e-o-s, such procedures will always
       leave at least 256 bytes (512-256) left in the stack.

       For procedures that use more than 256 bytes:
               mov     eax,esp
               sub     eax,Stack_margin_2
               cmp     eax,Amount_to_allocate
               jae     around
               int     0
       around: ...

       Since Stack_margin1 is 256 from true end,
       such procedures will leave at least 256 bytes in the stack.

    Therefore, stack overflow occurs when less than 256 bytes would be
    left AFTER stack allocation.
    This permits the run-time environment to do some processing
    such as producing a trace or cleaning up.
%
comment @
 --------------------------------------------------------------------------
  AutoDesk Compatibility
 --------------------------------------------------------------------------
        Modified for AutoLISP and protected 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.

        DX: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 protected 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.
        @
 
minmem equ 4    ; Offset within the structure containing initialization
                ; information to the initial 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 protected mode ADI driver.
endif   ; PADI

;---------------------------------------------------------------------------
; Start of program code.
;---------------------------------------------------------------------------
	.386p		; Need p to execute "lsl" to determine limit
			; of data segment.
	.287
	name    init
	include	init.inc	; defaults moved into init.inc
				; several assemblies use them.
				; init.asm, init_67.asm init_87.asm

	; The following include file is provided by IGC.
	; GDA.STR is general data area structure for VM/RUN (X-AM).
	; Upon entry to target program from VMRUN, EDX --> GDA.
	; GDA is not useful when solely in the Phar-Lap environment.
	; Use "gda.h" in the inc/ directory to access the GDA from C:
	;
	; 	#include "gda.h"
	;	GDA *gdaptr;
	include gda.str

;--------------------------------------------------------------------------
;  Fix segment ordering.
;--------------------------------------------------------------------------
    ; The following dummy segment instructs linker to put "code" lowest
    ; Must be made public since the main module also has public code,
    ; and some primitive linkers can't handle segments of the same name
    ; with different privacy attributes.  (This does not include Phar Lap's
    ; linker.)

;-- stack segment ----------------------------------------------------------
if      eWINDOWS

; stack comes before code in windows

; Use dword alignment for stack segment in the future.

STACK? segment dword stack 'STACK'   ; of at least 80 bytes.
; Copyright message got moved out of here so that the stack wouldn't
; take up space in the .exe file.

start_of_stack equ this byte
        db      STACK_SIZE dup (?)      ; The default stack of 64K.
STACK? ends                     ; MS-DOS loader puts info at the
                                        ; tail end of the stack during loading.
endif

;-- code segment ----------------------------------------------------------
_TEXT   segment dword public 'CODE'
_TEXT   ends

;-- data segment ----------------------------------------------------------
_DATA   segment dword public 'DATA'
        pubname stack_limit
The_stack_margin equ this word
def     stack_limit,dd,0        	; Stack margins.
        dd      0
_DATA    ends

;-- const segment ----------------------------------------------------------
CONST	segment	public 'CONST'
CONST	ends

;-- bss segment ----------------------------------------------------------
_BSS	segment	public 'BSS'
_BSS	ends


;-- end bss segment ----------------------------------------------------------
_EBSS_	segment public 'BSS'
_ebss	equ this byte
_EBSS_	ends


;-- stack segment ----------------------------------------------------------
if not eWINDOWS

;    stack comes after BSS if not windows

if	not eUSING_MASM

; Use dword alignment for stack segment in the future.
STACKNAME equ ?STACK

STACKNAME segment dword stack 'STACK'   ; of at least 80 bytes.
; Copyright message got moved out of here so that the stack wouldn't
; take up space in the .exe file.

start_of_stack equ this byte
        db      STACK_SIZE dup (?)	; The default stack of 8K.
STACKNAME ends    			; MS-DOS loader puts info at the
					; tail end of the stack during loading.

else  ; eUSING_MASM

; Use dword alignment for stack segment in the future.

?STACK segment dword stack 'STACK'   ; of at least 80 bytes.
; Copyright message got moved out of here so that the stack wouldn't
; take up space in the .exe file.

start_of_stack equ this byte
        db      STACK_SIZE dup (?)	; The default stack of 8K.
?STACK ends    			; MS-DOS loader puts info at the
					; tail end of the stack during loading.
endif ; not eUSING_MASM
endif ; not eWINDOWS

;---------------------------------------------------------------------------
;  Line terminator convention.
;---------------------------------------------------------------------------
    ; This must be a MetaWare Pascal string:  2 bytes for the length,
    ; then the actual string characters follow.
    ; Even if the string is of length one, leave the length of this
    ; segment at 8 bytes. (leave lt2 present even if not used.)
    ; Line termination convention for input:

_MWLTCONV       segment common dword 'DATA'
ltconv_in       dw      0       ; length is 2 for line terminator.
				; zero says allow either char for line term.
lt1i            db      13      ; CR
lt2i            db      10      ; LF
; Line termination convention for output; must be length of one or two chars.
ltconv_out      dw      2       ; length is 2 for line terminator.
lt1o            db      13      ; CR
lt2o            db      10      ; LF
_MWLTCONV       ends

;---------------------------------------------------------------------------
;  Call on entry segments
;---------------------------------------------------------------------------
    ; This segment is used to 'register' functions which must be called
    ; by the start-up routine.  Each of the functions to be called
    ; contain the following three segments, of which the first and last
    ; are empty. The central segment contains zero or more pointers to
    ; routines that the initializer must call during startup.
PUBLIC __mwdfc, __mwdlc
if eHC
_MWIFC	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWIFC	; hushes up MASM 5.1 errors
	endif
__mwifc label near
_MWIFC	ends
_MWIMC	segment	public word 'DATA'
_MWIMC	ends
_MWILC	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWILC	; hushes up MASM 5.1 errors
	endif
__mwilc label near
_MWILC	ends
_MWDFC	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWDFC	; hushes up MASM 5.1 errors
	endif
__mwdfc	label near
_MWDFC	ends
_MWDMC	segment	public word 'DATA'
_MWDMC	ends
_MWDLC	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWDLC	; hushes up MASM 5.1 errors
	endif
__mwdlc	label near
_MWDLC	ends
; the following for use in windows's adk destructor, previously conflict
; with C++ destructor.
if      eWINDOWS
PUBLIC __mwdfw, __mwdlw
_MWDFW	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWDFW	; hushes up MASM 5.1 errors
	endif
__mwdfw	label near
_MWDFW	ends
_MWDMW	segment	public word 'DATA'
_MWDMW	ends
_MWDLW	segment	public word 'DATA'
	if eUSING_MASM_51
	assume  cs:_MWDLW	; hushes up MASM 5.1 errors
	endif
__mwdlw	label near
_MWDLW	ends
endif
endif

;--------------------------------------------------------------------------
;  Start of data segment.
;--------------------------------------------------------------------------
DSEG    segment dword 'DATA'

    ;----------------------------------------------------------------------
    ;  Public symbol declarations.
    ;----------------------------------------------------------------------
        ; The symbols declared with the defequ or pubnames macros are
        ; prefixed with "_mw".  Input and output are for Pascal but must be
	; provided in C if we link in the C initializer with Pascal routines.

        pubnames <input,output>
        pubnames <es,is_286,envp,8087,387,1167>
        pubnames <argp,arglen,prognamep>
        pubnames <CPU,OS,env,wind,printnochipmsg,init_ver>
	pubnames <emc87,heap_expansion_enabled>
        extrn   _osmajor:byte,_osminor:byte
	if eHC
        pubname argvp
	endif

	; Define input and output descriptors
	; Pascal file variables Input and Output.
	; They are initialized in Pascal's Finit.p.

defequ  input,dw,0
defequ  output,dw,1

    ;----------------------------------------------------------------------
    ;  Initialize the "host" package.
    ;----------------------------------------------------------------------
        ; Initialize the "host" package that identifies the system we're
        ; running on.  See the interface file Host.pf distributed with
        ; Professional Pascal or High C for the enumerated type declaration
        ; for the values of CPU and OS.

defequ  CPU,db,8        ; Indicates 386.
defequ  OS,db,0         ; Indicates MSDOS.

    ;----------------------------------------------------------------------
    ;  Initialize the graphics selector.
    ;----------------------------------------------------------------------
        ; The startup code detects the host environment and sets the graphics
	; selector accordingly.  This info is used by GFX.

defequ	gsel,dw,0	; graphics selector
public	_mwgsel 	; Pharlap (PL_env) uses 1C
			; Eclipse (AI_env) uses B8 and B0

    ;----------------------------------------------------------------------
    ;  Data definitions.
    ;----------------------------------------------------------------------

STDERR  equ     2      		; standard error file handle
_psp    equ     this byte
def     es,df,0
	; The contents of es prior to invoking program
        ; df is Microsoft's way of saying 48-bit pointer;
        ; Phar Lap uses dp or df.
escontents equ _psp             ; Program segment prefix pointer.
envptr  equ 2CH       		; Offset in DOS ctrl block where env address
				; is located

ifdef	STACK_SIZE
        public  _top,_base,_psp
_top          dd    0		; Top of stack (relative to SS).
_base	      dd    0		; Base of stack (relative to DS).
_heaphi       dd    0           ; offset to top of system heap
_heaptop      dd    0           ; offset to top of previous heap request
                                ; (heaptop+1)..(heaphi) is available

osver	      dd	?	; all 32 bits of os version
virtbase      dd	?       ; ptr to allocated memory
totsize       dd        ?       ; total size of request
lasthand      dw 2 dup (?)	; last handle allocated

ifdef   SG_exists
        public  _gda
_gda    dd      0               ; Address of gda (softguard only)
endif	; SG_exists
endif	; STACK_SIZE

defequ  argp,df,?       	; Pointer to command arguments
if	eHC
defequ  argvp,df,?       	; Address of argv array for C.
endif   ; eHC

	even
if	eWINDOWS
	pubname is_p
if	not eHC
    defequ is_p,db,1		; Is the RTE Pascal or C?
else
    defequ is_p,db,0		; low-level interface clears errno
endif
endif

defequ  arglen,DD,?     	; Length of command argument string
defequ  envp,df,0       	; Pointer to environment string
defequ  is_286,db,0     	; True if this is a 286.

_8087   equ     this word       ; Need word to store control word into.
def     8087,dw,0       	; Set to true if 8087 is present
	db	0dh,0ah,'80x87$'
temp    dw      0

_387    equ     this word       ; Need word to store control word into.
def     387,dw,0        	; Set to true if 80387 is present.
	db	0dh,0ah,'80387$'

_1167   equ     this word
def     1167,dw,0       	; True if 1167 is present.

_emc87	equ	this word
def	emc87,dw,0		; Set to true if emc87 is present.
	db	0dh,0ah,'Cyrix EMC87$'

	public	_mwno87
_mwno87	dd	0		; pointer to no87 environment string.
_mwno87es dw	0,0		; MUST immediately follow mwno87!!!!!!

savefs	dw	0
Null_pname db   0       	; Null prog name for < DOS 3.0.

; Prognamep is initialized to a 32-bit pointer to a 0-byte in case
; we can't obtain the program name.
defequ  prognamep,dd,Null_pname	; Pointer to program name
        prognamep_seg dw 0

return_address equ this byte	; Used to save the return address before the
return_off	dd	0	; stack is set up.  We can then use a jump
return_seg	dw	0	; instruction to return.

SG_ENV = 1
PL_ENV = 2
AI_ENV = 3
SSI_ENV = 4
D4G_ENV = 5

defequ  env,db,0        	; Which environment are we in?  SG/PL/AI?
public _mwenv
defequ  wind,db,0        	; Are we running under windows?
defequ  printnochipmsg,db,0
defequ  init_ver,db,2		; Which init is this? (1==LOC,2==GOC)
Lahey_format_load_file db 0     ; .plx (Phar-Lap linked) by default.

; is heap expandable?
CANT_EXPAND = 0
CAN_EXPAND = 1
if eWINDOWS
    defequ	heap_expansion_enabled,db,CANT_EXPAND
else
    defequ	heap_expansion_enabled,db,CAN_EXPAND
endif

ifdef   ACAD
chkval  equ     1234                    ; magic interface-compatibility code
ifdef  ADS                              ; Avoid excess globals for ADS
info_off	equ	ads_info_off
info_sel	equ	ads_info_sel
else
        public  brkflg,stkflg
endif   ; ADS
        public  info_off,info_sel
ifdef   PADI
	align	4
        public  cbufadr
cbufadr  dd     0                       ; ptr to common pg between ACAD & 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
interr  db      "Incompatible program interface",0Dh,0Ah,"$"
rtnaddr df      0                       ; Caller's return address.
info_off dd     0                       ; Offset of initialization info struct
info_sel dw     0                       ; Selector of initialization info struct
min_mem dd      0                       ; initial driver heap size
endif   ; ACAD

PSPseg  dw      24h     ; Pointer to DOS's Program segment prefix: Phar Lap.
ENVseg	dw	2ch     ; Pointer to DOS's environment string: Phar Lap.
DSEG    ends

if eDOS
    if eWINDOWS
	DGROUP group _BSS,_DATA,DSEG,_MWIFC,_MWIMC,_MWILC,_MWDFC,_MWDMC,_MWDLC,_MWLTCONV, _MWDFW, _MWDMW, _MWDLW
    else
	if eUSING_MASM
	    DGROUP  group _BSS,_DATA,DSEG,_MWIFC,_MWIMC,_MWILC,_MWDFC,_MWDMC,_MWDLC,_MWLTCONV,_EBSS_
	else
	    DGROUP  group _BSS,_DATA,DSEG,_MWIFC,_MWIMC,_MWILC,_MWDFC,_MWDMC,_MWDLC,_MWLTCONV,STACKNAME,_EBSS_
	endif
    endif
else
    DGROUP  group _DATA,DSEG,_MWIFC,_MWIMC,_MWILC,_MWDFC,_MWDMC,_MWDLC,_MWLTCONV,STACKNAME,_EBSS_
endif

assume_dgroup macro
if	eUSING_FLAT
	assume	ds:FLAT
else	
	assume  ds:DGROUP
endif	
	endm

;--------------------------------------------------------------------------
;  Start of code segment.
;--------------------------------------------------------------------------
?INIT   segment dword 'CODE'
if	not eUSING_FLAT
CGROUP  group   ?INIT,_TEXT
        assume cs:CGROUP
else
FLAT  	group	?INIT,_TEXT
	assume cs:FLAT
endif

    ;---------------------------------------------------------------------------
    ;  Declare external procedures
    ;---------------------------------------------------------------------------
    ; Extern procs must be defined within current code segment for
    ; correct relocation bits to be generated.
    ; Phar lap assembler won't take next line; it plays according to the rules
    ; (as opposed to Microsoft's assembler):

    extrn   exit:near
if  eHC
    extrn   main:near       ; Main program entry point
    extequ  set_up_args,near; Routine to compute argv pointers.
else
    extequ  main,near       ; Main program entry point
endif

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

if not eUSING_FLAT
Stack_margin_big_place		equ	dword ptr DGROUP:The_stack_margin
Stack_margin_small_place	equ	dword ptr DGROUP:The_stack_margin+Word_size
else
Stack_margin_big_place		equ	dword ptr The_stack_margin
Stack_margin_small_place	equ	dword ptr The_stack_margin+Word_size
endif

    ;-------------------------------------------------------------------------
    ;  Here begins the execution of a Professional Pascal or High C program.
    ;-------------------------------------------------------------------------

init    proc
        publab  INIT    ; Compiler generates this in upper case.

	; INIT: Initialization code
	; - set initial stackpointer, framepointer
	; - jump to _CINIT function to continue initialization.
        assume_dgroup

	if	eHC
    	Small_data_HC = 1
	endif
	SETBLOCK equ 4Ah

	jmp	Start_init
	public	__main
__main:
	jmp	main

ifdef   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.
        @
ifndef  ADS                     ; Take care with public names in ADS
        public  exit_to_acad
endif
exit_to_acad:
        jmp     rtnaddr         ; Return to AutoCAD
endif   ; ACAD

Start_init:

ifdef   ACAD
        cmp     ecx,chkval              ; Proper chkval argument?
        je      m00
        mov     edx,offset interr       ; "Incompatible program interface"
        mov     ah,9
        int     21h                     ; Print the 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.
endif   ; ACAD

;       default assumptions
if eWINDOWS
	mov	env,SSI_ENV
else
;	determine OS version
	call	init_const

if ePL_exists
	mov     env,PL_ENV
endif

	; DOS|Extender environment discovery code obtained from Phar Lap:
if eSG_exists
	; IGC: eax = abcdabcd.  Also, code segment is privilege level 3
	; (= 43 hex).
	cmp     al,0cdh         ; eax = abcdabcd for IGC.
	jne     short not_sg
	cmp     ah,0abh
	jne     short not_sg
	; Flaw: If we are in non-protected mode and get this far,
	; the cmp eax will have 16 bits too much constant, and will
	; cause the initializer to bomb.  It is unlikely that ax=abcd
	; yet eax <> abcdabcd.  --fixed with shift sequence.
;;;	cmp     eax,0abcdabcdh  ; Now try 386 instruction.
	shr	eax,8
	cmp	ah,0cdh
	jne     short not_sg
	shr	eax,8
	cmp	ah,0abh
	jne     short not_sg
	mov     env,SG_ENV
	mov     _gda,edx
	jmp     short Initialize_everything
not_sg: 
endif ; SG_exists

if eD4G_exists
	; Magic code to figure out if this is Rational's 32-bit DOS extender.

	; jmp	force_rational		
	mov	dx,78h
	mov	ax,0ff00h
	call	_mwint21
	cmp	eax, 4734ffffh	; 4G
	jne	short not_d4g

force_rational:
        mov	env,D4G_ENV
	mov	ax, es
	mov	PSPseg, ax
	mov	bx,2Ch
	mov	ax,es:[bx]
	mov	ENVseg, ax
not_d4g:
endif ; D4G_exists

if eAI_exists
	cmp     env,D4G_ENV
	je      short not_ai
	cmp	env,SSI_ENV
	je	short not_ai
	mov	eax,osver
        shr     eax,16
        cmp     ax,'DX'
        je      short not_ai
        mov     env,AI_ENV
not_ai:
endif ; AI_exists
endif ; eWINDOWS

Initialize_everything:

	sub     ebp,ebp         	; Initialize stack frame pointer

	; Make sure stack is mod 4 in case it's not.
	and     esp,0fffffffch  	; Drop extra bytes.  Oh well.
	assume_dgroup

if      eWINDOWS
        ; Incoming registers:
        ; esi: initial amount of heap provided by loader, at tail end of DGROUP.
        ; ebx: pointer to argument strings.
        ; edi: pointer to program name.
        ; environ:
        ; ax:0:
        ;      (db 'var=value',0)*
        ;      (db 0)+          ; possibly some 0 padding for expansion later
        ; ax:edi:
        ;       db 'progname',0 ; fully-expanded (drive & path)
        ; ax:ebx:
        ;       db 'invoke name',0   ; the invocation prog name.
        ;       db 'arguments',0     ; 1 or more arguments.
        ;       db 0
        ; handle-table:
        ;       dd count
        ;       (db type, dd handle)*
        ;               type = 0 unused; 1 session; 2 file.

	cmp	env,SSI_ENV
	jne	next0
        mov     word ptr envp+Word_size,ax      ; Offset is already 0.
        ; mov   envp,0                          ; This is already 0.
        
        mov     word ptr argp+Word_size,ax      ; Offset of arguments.
        mov     dword ptr argp,ebx              ; Will be adjusted to skip prog 
                                                ; name later.
        
        mov     word ptr prognamep+Word_size,ax
        mov     dword ptr prognamep,edi         ; Save prog name offset.

	; initialize heap
	mov	_base,0
        mov     ax,ds
        lsl     eax,eax                 ; Find total space.
        mov     _heaphi,eax             ; End of heap.

        mov     _top,esi		; heap starts here
	mov	eax,esi			
	inc	eax	                ; increase size to page boundary
	add	eax,4095
	and	eax,0fffff000h
	dec     eax
	mov	_heaptop,eax            ; and this is where heap really starts
next0:
endif ; eWINDOWS

	; For the 386 we own all of memory.  Size up memory 
	; and inform the heap manager.
	mov     Stack_margin_big_place,Stack_margin_big
	mov     Stack_margin_small_place,Stack_margin_small
	add     Stack_margin_big_place,offset start_of_stack
	add     Stack_margin_small_place,offset start_of_stack

if eSG_exists
	; Initialize stack, IGC environemnt.
	; This code will work for h (highest) and a (append after load)
	; stk options. esp already setup by vmrun loader.
	cmp     env,SG_ENV
	jne     short next1

	mov     eax,esp         	; get stack pointer
	mov     ecx,[edx].GDA_STKSZ     ; get stack size, kbytes
	shl     ecx,10          	; convert from k to # of bytes
	sub     eax,ecx         	; calculate base of stack addr
	mov     _base,eax       	; stack base
	mov     eax,[edx].GDA_HLOD      ; get highest load address
	mov     _top,eax        	; bottom of heap

	inc	eax	                ; increase size to page boundary
	add	eax,4095
	and	eax,0fffff000h
	dec     eax
	mov	_heaptop,eax            ; end of previous heap

	mov     eax,[edx].GDA_HLOD      ; get highest load address
	mov     ecx,[edx].GDA_HMEM      ; get available high memory
	shl     ecx,10          	; convert from k to # of bytes
	add     eax,ecx         	; calculate heap top addr
	mov     _heaphi,eax     	; top of heap

	; Free memory below 640K for subsequent use by EXEC.
	mov     ebx,[edx].GDA_TLOW      ; Subtract highest used low address.
	sub     ebx,[edx].GDA_PSPA      ; Subtract lowest used low address.
	shr     ebx,4                   ; Convert to paragraphs.
	inc     ebx                     ; Safety?
	mov     ah,SETBLOCK             ; SETBLOCK to bx paragraphs from
	; psp start.
	call	_mwint21
	test    byte ptr [edx].GDA_ENV,GDA_WEITEK
	setne   byte ptr _1167
next1:
endif   ; SG_exists

if ePL_exists
	cmp     env,PL_ENV
	jne     short next2

	mov     _base,0         ; Start of stack.

;---------- BEGIN CHANGE FOR PHARLAP 6.0
;   see similar change (and explanation) in initheap.c from HC version 3.11
ifdef ACAD
	mov     eax,esp
else
	push	es
        mov     ax,4		; selector to PSP
        mov     es,ax
        mov     eax,es:[5ch]   ; Initial size of heap: load image size in bytes
	pop	es
endif	; ACAD

	mov     _top,eax
;---------- END CHANGE FOR PHARLAP 6.0

	inc	eax	        ; increase size to page boundary
	add	eax,4095
	and	eax,0fffff000h
	dec     eax
	mov	_heaptop,eax    ; end of previous heap

	mov	ax,fs
	mov	savefs,ax
	and     ax,ax   	; If fs = 0 (Lahey linker), can't have Weitek.
	sete    Lahey_format_load_file

	mov     ax,ds
	lsl     eax,eax         ; load segment limit of data segment.
	mov     _heaphi,eax     ; Top of heap (linear address).
next2:
endif  ; PL_exists

if eD4G_exists
        cmp     env,D4G_ENV	        ; One doesn't shrink the heap in DOS4G.
        jne	short next2a

	mov     _base,0
	mov     _top,esp
        mov	_heaphi,esp             ; previous top of heap
	mov     _heaptop,esp            ; top of heap (empty)
next2a:
endif

ifdef   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
	extrn	_cinit:near
if	eWINDOWS
	mov	wind,1
	call	_cinit
	db	0cbh			; retf
else
	jmp	_cinit
endif   ; eWINDOWS
init	endp

if	eHC
	db  'High C'
else
	db  'Professional Pascal'
endif
	db  ' Run-time Library Copyright (C) 1983-1992 MetaWare Incorporated.'

;-------------------------------------------------------------------------------
; init_const
;-------------------------------------------------------------------------------
init_const proc
	publab init_const
	prolog
	assume_dgroup
;	initialize constants ... may be called from init,
;       or from WINDOWS environment initializer

;	determine DOS version number
	push	eax
	push	ebx
        xor     eax,eax
        mov     ah,30h		; Get DOS version number
	call	_mwint21
        mov     word ptr _osmajor,ax    ; Moves minor (AH) and major (AL).
	mov	osver,eax	; also save full version locally
	pop	ebx
	pop	eax

	epilog
init_const endp

if	eDOS and not eWINDOWS
;-------------------------------------------------------------------------------
; init_env_area()
;-------------------------------------------------------------------------------
    ; Process environment area and parameter strings.

init_env_area proc
	publab init_env_area
	;assume	cs:CGROUP
	assume_dgroup

	Parm_string_offset = 80h       	; Offset in PSP containing parm
					; string (len+bytes).
					; Pop return address off of stack
	pop	dword ptr return_off
	ifdef	Small_data
	push	cs			; 32 bits?
	endif
	pop	eax			; Pop dword to maintain 
	mov	word ptr return_seg,ax	; stack alignment!

	cld                    		; All moves are forward

if eSG_exists
	cmp     env,SG_ENV
	jne      short next3

	; GDA has pointer to PSP.  PSP has env seg, which, shifted left by 4,
	; yields the 32 bit address of the env.
        mov     edi,[edx].GDA_PSPA      ; Get flat PSP address.
        mov     word ptr argp+Word_size,ds
        mov     dword ptr _psp,edi
        mov     word ptr _psp+Word_size,ds
        lea     eax,Parm_string_offset[edi] ; eax = pso+edi.
        xor     ebx,ebx
        mov     bl,[eax]       		; Get length of parm string.
        mov     arglen,ebx
        inc     eax
        mov     dword ptr argp,eax      ; Addr of parm string.
        mov     bx,envptr[edi]  	; Get segment address of
					; environment pointer.
        shl     ebx,4           	; Convert to 32-bit flat address.
        mov     dword ptr envp,ebx
        mov     word ptr envp+Word_size,ds ; Fill out 48-bit address
        jmp     more_init2
next3:
endif  ; SG_exists

if ePL_exists or eD4G_exists
	cmp     env,PL_ENV
	je      short next4a
	cmp     env,D4G_ENV
	jne     next4
next4a:
        cmp     Lahey_format_load_file,1
        je      short ES_points_to_PSP_already
        mov     ax,PSPseg
        mov     bx,cs
        arpl    ax,bx
        mov     es,ax           		; Load es with psp address.

        ; Load environment segment into cx.
        mov     cx,ENVseg
        arpl    cx,bx
        jmp     short more

ES_points_to_PSP_already:
        ; Load environment segment into cx.
        mov     cx,es:02ch
        mov     ax,es
more:
        mov     word ptr _psp+Word_size,ax      ; Construct 48-bit psp address.
        mov     word ptr escontents+Word_size,ax; No displacement
        mov     word ptr envp+Word_size,cx	; Environment segment.
        xor     eax,eax
	push	eax
        mov     al,es:Parm_string_offset 	; Length of parm string
	mov	arglen,eax

; In C, the parameter string must be moved to a DS-accessible area
; if small-data model.
if	eHC
;       Move the parm string into the stack so that it can be accessed by
;       small-data programs with only 16-bit pointers.
        mov     ecx,eax 	; parameter length
	inc	ecx
        add     al,3
        and     al,0fch 	; Make sure eax is multiple of 4.
        sub     esp,eax  	; Length of parm string.
        mov     edi,esp  	; Move the parameter string here.
        mov     dword ptr argp,edi ; Save address of args.
        ;push    edx     	; Allow byte for parm string overwrite
				; by C arg processor.  But make stack
				; word-aligned for efficiency.
        push    ds      	; Save it.
        push    es      	; source is es:81h
        pop     ds
        push    es      	; Save es.
        push    ss
        pop     es      	; Dest is ss:di.
        mov     esi, offset Parm_string_offset+1
        rep     movsb   	; es:di := parm string.
        pop     es
        pop     ds

else   ; not eHC
	; Large-data or Pascal model	
	; just store the address of the parms.
        mov     ax,word ptr escontents+Word_size
        mov     word ptr argp+Word_size,ax
        mov     dword ptr argp,Parm_string_offset+1     ; Addr of parm string.
endif  ; eHC

next4:
endif  ; PL_exists or D4G_exists

more_init2:

if eD4G_exists
        cmp     env,D4G_ENV
        je	no_change
endif

if eSG_exists
        cmp     env,SG_ENV
        je      no_change
endif

if eAI_exists
        cmp     env,AI_ENV
	jne     short not_ai2

        mov     ebx,_top                ; Top of stack in bytes

ifndef  AIA_CAN_GROW_HEAP
;       If Lahey format, we must be able to grow.
        cmp     Lahey_format_load_file,1
        jne     short no_change
endif

        jmp     short Free_up
not_ai2:
endif   ; AI_exists

if      ePL_exists
ifndef  PHAR_LAP_CAN_GROW_HEAP
        jmp     short no_change
else
        ; Now free all of the heap, so that we
	; allocate more only when necessary.
ifdef   ACAD
 
ifdef   PADI
        mov     ebx,_top                ; Get top of stack
        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,SETBLOCK             ; 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
	dec	ebx
        mov     _heaptop,ebx
	and	ebx, 0fffffffch
        mov     _top,ebx                ; Assumption made _top is heap bottom
else    ; PADI
        mov     ebx,_top                ; Get top of stack
        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,SETBLOCK             ; Set memory size to smallest #
        int     21h                     ;   of pages ecompassing 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
        or      eax,eax                 ; Any pages mapped?
        jz      no_map
        add     ebx,eax                 ; If so, add it in
        shl     ebx,12                  ; Get bottom of heap, in bytes
	dec	ebx
        mov     _heaptop,ebx
	and 	ebx, 0fffffffch
        mov     _top,ebx                ; Assumption made _top is heap bottom
no_map:
endif   ; PADI
 
        mov     ebx,min_mem             ; Initial size of heap
else    ; ACAD
        mov     ax,4
        mov     es,ax
        mov     ebx,es:[5ch]   ; Initial size of heap: load image size in bytes.
                               ; See Phar Lap TN #21.
endif   ; ACAD
        jmp     short Free_up
endif   ; PHAR_LAP_CAN_GROW_HEAP
endif   ; PL_exists

if ePL_exists or eAI_exists
Free_up:
        add     ebx,4095                ; Round up to pages.
        shr     ebx,12                  ; Convert to 4K pages.

ifdef   ACAD
ifdef   PADI
        ; Initial heap size, set up in min_mem above with a minimum
        ; heap value that comes from the loader in AutoCAD, does not
        ; account for the extra page added on as a result of the page
        ; mapping done above to obtain access to a buffer common with
        ; AutoCAD.  Therefore, the number of pages for the initial
        ; heap size is increased by one.
 
        inc     ebx
 
endif   ; PADI
 
        ; Any additional pages mapped onto the segment as a result of
        ; calling map_phys_mem() above is added here.
 
        add     ebx,eax                 ; Add add'l pgs mapped by 3rd party
endif   ; ACAD

        inc     ebx                     ; Add 1 page for initial heap.

        mov     edx, ebx
        shl     edx,12                  ; Future value for heaphi.
	dec     edx

        cmp     env,PL_ENV
        je      short No_para
        shl     ebx, 8                  ; Convert to paragraphs for AIA.
No_para:
        push    ds
        pop     es                      ; Segment to free up.
        mov     ah,SETBLOCK             ; SETBLOCK to bx paras from psp start.
	call	_mwint21
        jc      short no_change         ; If couldn't get the extra page, oops!
        mov     _heaphi,edx
endif   ; PL_exists or AI_exists


no_change:

; find program name...
;     -- Format of DOS environment:              VVV 3.x only VVV
;     -- t1 nul t2 nul t3 nul ... tn nul nul x x program-name nul
; Go to end of environment string to get program name for DOS 3.0.
; While we're doing so, see if he said "NO87=" something, in which case,
; mimicking Microsoft's emulator, we print the string (unless it's
; nothing but blanks), and disable use
; of the 80287 if the combination emulation/80287 library is linked in.

        les     edi,envp        ; Pointer to environment area.
        xor     eax,eax         ; search for 0 byte.
Scan_again:
        cmp     dword ptr es:[edi],'78ON'   ; NO87
        jne     short not1
        cmp     byte ptr es:4[edi],'='   ; =
        jne     short not1

; All this fuss just to print the NO87 string!
ifndef  no87
	add	edi,5
	mov	_mwno87,edi
	mov	_mwno87es,es	;save pointer and print it later.
endif   ; no87

not1:	
	sub     ecx,ecx
	dec     ecx             ; ecx := -1
        repnz   scasb           ; Search for 0.
; We MUST have found the 0 byte; we're positioned at the byte after.
        cmp     byte ptr es:[edi],0     ; Two 0 bytes in a row?
        jne     Scan_again      ; Nope, keep going.

; 	Now we've found the environment area end.  
;	+3 bytes later is the prog name.
        add     edi,3           ; Move to program name.
        cmp     _osmajor,3      ; Program name supplied by OS?
        jb      short NO_PNAME_AVAIL
        cmp     env,SG_ENV
        jne     short get_pname
;       cmp     env,AI_ENV		** commented out 18-Jun92 (MJMauro)
;       je      short get_pname         **
        ; IGC: pname is addressable.
        mov     dword ptr prognamep,edi
        mov     word ptr prognamep+Word_size,ds
        jmp     short _prog_name

NO_PNAME_AVAIL:
; No program name.  Supply the null string.
if eHC
;       Allocate the null byte on the stack right after the parms.
        xor     edx,edx
        push    edx             ; Null byte(s).
        mov     dword ptr prognamep,esp  ; Pointer to the program name.
endif ; eHC
        jmp     short _prog_name
get_pname:

if ePL_exists or eD4G_exists or eAI_exists
	cmp     env,PL_ENV
	je      short next5a
	cmp     env,AI_ENV
	je      short next5a
	cmp     env,D4G_ENV
	jne     next5
next5a:

; In small-data C, the program name must be moved into the DS group.
ifdef   Small_data_HC           ; Move the program name to the stack.
        mov     ax,es
        lsl     eax,eax         ; load segment limit of env string.
        xor     eax,eax
        ; Find length of program name.
        sub     ecx,ecx
        dec     ecx
        mov     ebx,edi         ; Save starting address of name.
        repnz   scasb
        sub     edi,ebx         ; Length of name (including 0 trailer).
        lea     eax,3[edi]      ; Add some space on stack...
	and	al,0fch		; only al involved, so use shorter instructions.
        sub     esp,eax         ; Allocate space for name.
        mov     dword ptr prognamep,esp  ; Where the name will be put.
        mov     ecx,edi         ; Length of name
        mov     esi,ebx         ; Name is stored here.
        mov     edi,esp         ; Copy to here.
        push    ds
        mov     ds,word ptr envp+Word_size
        push    ss
        pop     es
        rep     movsb
        pop     ds
else
        ; Non-small data case:  just record the address.
        mov     dword ptr prognamep,edi
        mov     word ptr prognamep+Word_size,es
endif   ; Small_data_HC

next5:
endif   ; PL_exists or D4G_exists or AI_exists

_prog_name:
if eHC
	; Now allocate the space for the argv pointers.  One for the program 
	; name and one for each argument.  Although we don't know how many 
	; arguments there are, there can be at most 1 for every two characters 
	; of the environment string.
	mov     eax,arglen
	inc     eax
	shr     eax,1   ; Max arg ptrs for parameters
	inc     eax     ; Count the program name.
	inc     eax     ; ANSI requires argv[argc] = null pointer.
	shl     eax,2   ; Multiply by pointer size
	sub     esp,eax ; Now allocate it.
	mov     dword ptr argvp,esp      ; sp is here.
endif   ; HC

	jmp	fword ptr return_address
init_env_area endp
endif   ; eDOS and not eWINDOWS



;-------------------------------------------------------------------------------
; clear_bss()
;-------------------------------------------------------------------------------
clear_bss proc
	publab	clear_bss
	prolog eax,ecx,edi

    assume_dgroup

	extrn	_edata:near
	extrn	_end:near

	xor	eax,eax
  	mov	edi,offset ds:_edata
  	;mov	ecx,offset ds:_end
  	mov	ecx,offset ds:_ebss
	sub	ecx,edi
	
	shr ecx,1
	rep stosw
	adc ecx,ecx
	rep stosb ; Could be smarter -- use stosd, but compilcates code
	epilog
clear_bss endp

;-------------------------------------------------------------------------------
; call_onentry_fcns()
;-------------------------------------------------------------------------------
call_onentry_fcns proc
	publab	call_onentry_fcns
	prolog

        assume_dgroup
        push    ds
        pop     es
	mov	ax,fs
	mov	savefs,ax
        ; ss is already = ds.

	; Clear BSS segment
if	eD4G_exists
  if	not eWINDOWS
	call	clear_bss
  endif
endif

; Here begins new code...C++ initialization is done in C, so we just set up
; and call a C routine to do the work.

; typedef struct {
;	ulong	init_level;
;	void (*ct)();
;	ulong	reserved;
;	} ct_elem, *ct_array;
; void _mwdo_ctors(ct_array ctors, int ctor_size, ct_array dtors, int dtor_size)


	mov	ebx,offset _MWDFC
	mov	ecx,offset _MWDLC
	sub	ecx,ebx
	push	ecx			; Size of destructor array
	push	ebx			; Beginning of destructor array
	mov	ebx,offset ds:__mwifc
	mov	ecx,offset ds:__mwilc
	sub	ecx,ebx
	push	ecx			; Size of constructor array.
	push	ebx			; Beginning of constructor array
	extrnf	_mwdo_ctors
	call	_mwdo_ctors
	add	esp,10h			; pop 4 

	; Set graphics selector _mwgsel according to the environment
	; and equipment configuration. 
	;
if ePL_exists
	cmp	env,PL_ENV		;Is this Pharlap's environment?
	jne	short next10
	mov	gsel,1ch		;Pharlap uses 0x1c
next10:
endif

if eD4G_exists
	cmp	env,D4G_ENV
	jne	short next10a
	mov	ax, ds
	mov	gsel, ds		; use flat
next10a:
endif

if eAI_exists
	cmp	env,AI_ENV		;OS386?
	jne	short next11
AI_sel:
	mov	ah,12h			;OS386 has different selectors
	mov	bl,10h			;for color and bw.
	int	10h			;ask the BIOS which it is
	and	bh,bh
	jz	color
b_and_w:
	mov	gsel,0b0h		;OS386 bw selector is 0xb0
	jmp	short selector_is_set
color:
	mov	gsel,0b8h		;OS386 color selector is 0xb8
	jmp	short selector_is_set
next11:
endif

selector_is_set:

	epilog
call_onentry_fcns endp

;--------------------------------------------------------------------------
;       procedure Expand_Heap();
;--------------------------------------------------------------------------
; The heap manager calls this routine to expand the heap when it
; detects a heap overflow.  The expansion expands allocates more memory
; starting at _heaptop+1,  recording the new top-of-heap in _heaptop.
; If expansion is required, heaphi is adjusted.
; Currently this is implemented only for Phar Lap's DOS|Extender.

expand_heap proc far

	publab	expand_heap
	prolog

	parm386 <<request,dword>>
	parm86  <<request,dword>>

	mov	eax, request
	mov     virtbase,0
        mov     ebx,_heaphi            ; our upper-bounds
	sub     ebx,_heaptop           ; space left in heap
	cmp     eax,ebx                ; is it big enough?
	ja      short get_more

	mov     eax,_heaptop           ; compute start of new user heap
	inc     eax  
	mov     virtbase,eax
	dec     eax 

	add     eax,request            ; compute new heaptop
	mov     _heaptop,eax 
	jmp     return_from_expand

get_more:
        cmp     env,D4G_ENV
  	jne	not_dos4g

;       ***********************
;       *                     *
;       *       DOS4G         *
;       *                     *
;       ***********************
	mov     ebx,request             ; user request is multiple of 4k
        shrd	ecx,ebx,16	
        shr	ecx,16
	shr	ebx,16
        mov	ax,0501h
        int	31h
	jc	return_from_expand

	; Answer comes back in bx:cx.
	shl	ebx,16
	mov	bx,cx		        ; Form 32-bit address in ebx.

	; Handle comes back in si:di
	mov	lasthand,si
	mov	lasthand+2,di

	mov	virtbase,ebx
	mov	ecx,request             ; amount requested
	add	ecx,ebx		        ; add virtual base
	mov	_heaptop,ecx	        ; user top of heap
	mov	_heaphi,ecx	        ; same as system top of heap

 	jmp	return_from_expand

not_dos4g:
;       ***********************
;       *                     *
;       *     NOT DOS4G       *
;       *                     *
;       ***********************

        ; Has the user shut off heap expansion?  
        cmp	heap_expansion_enabled,CANT_EXPAND
        je	return_from_expand
        cmp     env,PL_ENV

ifndef  PHAR_LAP_CAN_GROW_HEAP
	je      return_from_expand ; Must have release >= 1.1t.
else
	je	short Can_grow    
endif   

ifndef	AIA_CAN_GROW_HEAP
;       If Lahey format, we must be able to grow.
	cmp	Lahey_format_load_file,1
	jne     short return_from_expand
else    
	cmp     env,AI_ENV
	jne	return_from_expand
endif   

Can_grow:
if not	eWINDOWS
        mov	ax,ds                   ; find top of heap
        lsl	eax,eax
	cmp     eax,_heaphi             ; if different, reset heap
	je      grow

        mov     _heaptop,eax            ; reset heap, as non-malloc request
	mov     _heaphi,eax             ; is blocking our request
	jmp     short grow

grow:
	mov     eax,_heaptop            ; next page starts on next byte
        inc     eax                     ; size = offset + 1
	add     eax,request             ; add in request
	mov     totsize,eax             ; save total size for later

	shr	eax,12                  ; convert to pages
	cmp     env,AI_ENV
	jne	short pages
	shl	eax,8		        ; convert pages to paragraphs for AI.

pages:	
	mov     ebx,eax                 ; prepare for INT 21h
	mov	ah,SETBLOCK
	call	_mwint21
	jc	short return_from_expand

	mov     eax,_heaptop            ; next page starts on next byte
	inc     eax                     ; new user heap will start here
	mov     virtbase,eax

	mov     eax,totsize             ; retrieve total size of request
	dec     eax                     ; convert to offset
	mov     _heaphi,eax             ; update pointers
	mov     _heaptop,eax
endif ; eWINDOWS

return_from_expand:
	mov     eax,virtbase
	epilog
expand_heap endp	


;-------------------------------------------------------------------------
;       procedure set_stack_limits(small,large:Cardinal);
;-------------------------------------------------------------------------
;       Set the two limits.
;       This is called by the heap manager when the heap begins to creep
;       into the stack, or when the heap has left the stack area.
;       Basically, when the heap has used the lower portion of the stack,
;       the stack margin variables are set to reflect a higher bottom-of-stack
;       location, so that stack overflow will occur when the stack is within
;       256 bytes of the heap.
;       If the stack precedes the heap, the heap never creeps into the
;       stack and this procedure will never be called.

Set_stack_limits        proc    far
        publab  set_stack_limits
        return  8
Set_stack_limits        endp

;-------------------------------------------------------------------------
;       function ss: Cardinal; {Returns paragraph address of stack segment
;-------------------------------------------------------------------------
ssx     proc    far
        publab  ss
        mov     ax,ss
        return
ssx     endp

;-------------------------------------------------------------------------
;       function Getds: Cardinal;       -- Returns ds register.
;-------------------------------------------------------------------------
;       This function may actually no longer be needed.
ifdef   Small_data
getds   proc    far
        publab  getds   ; return ds register.
	xor	eax,eax
        mov	ax,ds
        return
getds   endp

getcs   proc    far
        publab  getcs   ; return cs register.
	xor	eax,eax
        mov	ax,cs
        return
getcs   endp
endif

_exit   proc    near			;force an immediate exit to dos.
        public  _exit
        mov     eax, esp
        mov     al, [eax+4]
        mov     ah, 4ch
	call	_mwint21
_exit   endp

; void contract_heap (void *allocated)
;     memory, starting at *allocated, is returned to the system
contract_heap proc near
	publab contract_heap
	prolog

	parm386	<<loc,dword>>
	parm86	<<loc,dword>>

        cmp     env,D4G_ENV
  	jne	not_dos4g2

;       ***********************
;       *                     *
;       *       DOS4G         *
;       *                     *
;       ***********************

;	return memory to system
	mov	si,lasthand
	mov	di,lasthand+2
        mov	ax,0502h
        int	31h
	jc	return_fail
	jmp	return_okay

not_dos4g2:
;       ***********************
;       *                     *
;       *     NOT DOS4G       *
;       *                     *
;       ***********************

;	return memory to system
	mov	eax,loc
	shr	eax,12                  ; convert to pages
	cmp     env,AI_ENV
	jne	short pages2
	shl	eax,8		        ; convert pages to paragraphs for AI.

pages2:	
	mov     ebx,eax
	mov	ah,SETBLOCK
	int	21h
	jc	short return_fail

return_okay:
;       adjust _heaphi
	mov	eax,loc
	dec	eax
	mov	_heaphi,eax		; _heaphi := totsize - 1

;       if _heaptop > _heaphi, then adjust _heaptop
	cmp	eax,_heaptop
	jge	return_from_contract
	mov	_heaptop,eax		; _heaptop := _heaphi
	jmp	return_from_contract

return_fail:
;	adjust _heaptop, as we now have room
	mov	eax,loc
	dec	eax
	mov	_heaptop,eax

return_from_contract:
	epilog
contract_heap	endp

?INIT   ends
        end     init
