;[]------------------------------------------------------------[]
;|      C0D.ASM -- Start Up Code For Windows DLLs               |
;|                                                              |
;|      Turbo C++ Run Time Library                              |
;|                                                              |
;|      Copyright (c) 1987, 1991 by Borland International Inc.  |
;|      All Rights Reserved.                                    |
;[]------------------------------------------------------------[]

                locals

                __C0__ = 1
include         RULES.ASI

                ASSUME CS:_TEXT, DS:DGROUP

                public  __acrtused              ;satisfy MS for now
__acrtused      equ     0

                public __exitclean
                public __exit

                extrn LIBMAIN:far       ;the C routine to be called
                extrn LOCALINIT:far     ;Windows heap init routine
                extrn LOCKSEGMENT:far
                extrn UNLOCKSEGMENT:far
                extrn GETWINFLAGS:far
                extrn __WEP:far

                extrn __exitbuf:DIST
                extrn __exitfopen:DIST
                extrn __exitopen:DIST

                public LibEntry         ;Entry point for the DLL
                publicdll WEP

NULL            segment
                db      16 dup (?)
                ends

_CVTSEG         segment
                public __RealCvtVector
__RealCvtVector label word
                ends

_SCNSEG         segment
                public __ScanTodVector
__ScanTodVector label word
                ends

_FPSEG          segment
                public __FPVector
__FPVector      dd      0
                ends

_DATA           segment
                public _errno
_errno          dw      0
                public __protected
__protected     dw      0
                public __8087
__8087          dw      0
                public __version
__version       label word
                public __osversion
__osversion     label word
                public __osmajor
__osmajor       db      0
                public __osminor
__osminor       db      0
                public __osmode         ;Used for OS/2 protected mode by MS, 
__osmode        db      0               ;currently set to 0 under Windows
                public __hInstance
__hInstance     dw      0
                public __WinAllocFlag   ;Used by malloc for additional flags
__WinAllocFlag  dw      0               ;to pass to GlobalAlloc (used in DLLs)

_abend          dw      0               ;gets set to 1 if DLL is terminated
                                        ;by a call to abort() or _exit().

CopyRight       db      'Borland C++ - Copyright 1991 Borland Intl.',0
                ends

_TEXT           segment

LibEntry        proc far
                mov     __hInstance, di ;save SI and DI
                push    si

                push    di              ;handle of the module instance
                push    ds              ;library data segment
                push    cx              ;heap size
                push    es              ;command line segment
                push    si              ;command line offset

                ;if we have some heap then initialize it
                jcxz    @@Init          ;jump if no heap specified

                ;call the Windows function LocalInit() to set up the heap
                ;LocalInit((LPSTR)start, WORD cbHeap);

                push    ds              ;Heap segment
                xor     ax,ax
                push    ax              ;Heap start offset in segment
                push    cx              ;Heap end offset in segment
                call    LOCALINIT
                xchg    ax,cx
                jcxz    @@Exit          ;quit if it failed

@@Init:

IF LDATA EQ false
                mov     ax,-1
                push    ax
                call    LOCKSEGMENT
ENDIF

                ;Clear _BSS, uninitialized data area

                xor     ax, ax
                push    ds
                pop     es
                mov     di,offset DGROUP:BeginBSS
                mov     cx,offset DGROUP:EndBSS
                sub     cx,di
                cld
                rep
                stosb

;Determine DOS version

                mov     ah, 30h
                int     21h
                mov     __version, ax   ; save minor and major revision
 
;Determine whether we are in protected mode

                call    GETWINFLAGS
                test    ax,1            ; WF_PMODE = 1
                jz      @@realmode      ; Note:  GETWINFLAGS returns a long,
                                        ; so if WF_PMODE changed it could be 
                                        ; in the high word.
                mov     __protected, 8  ; Eight is for convenience.
@@realmode:

;Test for 8087 presence

                test    dx,04h          ; WF_8087 = 0x0400
                jz      @@no8087
                mov     __8087, 1
@@no8087:

;Call our initialization functions, including C++ static constructors.

                mov     ax,ds
                mov     es,ax
                mov     si,offset DGROUP:InitStart      ;si = start of table
                mov     di,offset DGROUP:InitEnd        ;di = end of table

                mov     __WinAllocFlag, 2000h           ; GMEM_SHARE
                call    Initialize
                mov     __WinAllocFlag, 0

                ;invoke the C routine to do any special initialization
@@Main:         call    LIBMAIN         ;invoke the 'C' routine (result in AX)
                mov     di, __hInstance ;restore SI and DI
                pop     si
                ret

@@Exit:         mov ax, 0               ;set return code
                pop si                  ;remove arguments to LIBMAIN
                pop es                  ;  since we didn't call it. 
                pop cx
                pop ds
                pop di                  
                pop si                  ;restore saved SI.  DI is restored 
                ret                     ;  by removing arguments to LIBMAIN
                endp

__exit          proc
                mov _abend, 1
__exitclean:
                mov al,[bp+cPtrSize]
                mov ah,4ch
                int 21h
                ret
                endp

WEP             proc    windows pascal far nParam:WORD
                push    si
                push    di

                cmp     _abend, 0
                jne     @@error
                push    nParam
                call    __WEP
                push    ax

                mov     ax,ds
                mov     es,ax
                mov     si,offset DGROUP:ExitStart
                mov     di,offset DGROUP:ExitEnd
                call    Cleanup

IF LPROG
                call    dword ptr [__exitbuf]
                call    dword ptr [__exitfopen]
                call    dword ptr [__exitopen]
ELSE
                call    word ptr [__exitbuf]
                call    word ptr [__exitfopen]
                call    word ptr [__exitopen]
ENDIF

@@unlock:

IF LDATA EQ false
                mov     ax,-1
                push    ax
                call    UNLOCKSEGMENT
ENDIF

                pop     ax  
                pop     di
                pop     si
                ret

@@error:
                push    1
                jmp     @@unlock
                
                endp


;------------------------------------------------------------------
;  Loop through a startup/exit (SE) table, 
;  calling functions in order of priority.
;  ES:SI is assumed to point to the beginning of the SE table
;  ES:DI is assumed to point to the end of the SE table
;  First 64 priorities are reserved by Borland
;------------------------------------------------------------------
PNEAR           EQU     0
PFAR            EQU     1
NOTUSED         EQU     0ffh

SE              STRUC
calltype        db      ?                       ; 0=near,1=far,ff=not used
priority        db      ?                       ; 0=highest,ff=lowest
addrlow         dw      ?
addrhigh        dw      ?
SE              ENDS

Initialize      proc near
@@Start:        mov     ah,0ffh                 ;start with lowest priority
                mov     dx,di                   ;set sentinel to end of table
                mov     bx,si                   ;bx = start of table

@@TopOfTable:   cmp     bx,di                   ;and the end of the table?
                je      @@EndOfTable            ;yes, exit the loop
                cmp     es:[bx.calltype],NOTUSED;check the call type
                je      @@Next
                cmp     es:[bx.priority],ah     ;check the priority
                ja      @@Next                  ;too high?  skip
                mov     ah,es:[bx.priority]     ;keep priority
                mov     dx,bx                   ;keep index in dx
@@Next:         add     bx,SIZE SE              ;bx = next item in table
                jmp     @@TopOfTable

@@EndOfTable:   cmp     dx,di                   ;did we exhaust the table?
                je      @@Done                  ;yes, quit
                mov     bx,dx                   ;bx = highest priority item
                cmp     es:[bx.calltype],PNEAR  ;is it near or far?
                mov     es:[bx.calltype],NOTUSED;wipe the call type
                push    es                      ;save es
                je      @@NearCall

@@FarCall:      call    DWORD PTR es:[bx.addrlow]
                pop     es                      ;restore es
                jmp     short @@Start

@@NearCall:     call    WORD PTR es:[bx.addrlow]
                pop     es                      ;restore es
                jmp     short @@Start

@@Done:         ret
                endp

Cleanup         proc near
@@Start:        mov     ah,0                    ;start with highest priority
                mov     dx,di                   ;set sentinel to end of table
                mov     bx,si                   ;bx = start of table

@@TopOfTable:   cmp     bx,di                   ;and the end of the table?
                je      @@EndOfTable            ;yes, exit the loop
                cmp     es:[bx.calltype],NOTUSED;check the call type
                je      @@Next
                cmp     es:[bx.priority],ah     ;check the priority
                jb      @@Next                  ;too low?  skip
                mov     ah,es:[bx.priority]     ;keep priority
                mov     dx,bx                   ;keep index in dx
@@Next:         add     bx,SIZE SE              ;bx = next item in table
                jmp     @@TopOfTable

@@EndOfTable:   cmp     dx,di                   ;did we exhaust the table?
                je      @@Done                  ;yes, quit
                mov     bx,dx                   ;bx = highest priority item
                cmp     es:[bx.calltype],PNEAR  ;is it near or far?
                mov     es:[bx.calltype],NOTUSED;wipe the call type
                push    es                      ;save es
                je      @@NearCall

@@FarCall:      call    DWORD PTR es:[bx.addrlow]
                pop     es                      ;restore es
                jmp     short @@Start

@@NearCall:     call    WORD PTR es:[bx.addrlow]
                pop     es                      ;restore es
                jmp     short @@Start

@@Done:         ret
                endp

                ends
                end LibEntry

