*
* C initial startup procedure under AmigaDOS
* 
* Use the following command line to make c.o
* asm -u -iINCLUDE: c.a
*
* Use the following command line to make cres.o
* asm -u -dRESIDENT -iINCLUDE: -ocres.o c.a
*
        INCLUDE "exec/types.i"
        INCLUDE "exec/alerts.i"
        INCLUDE "exec/nodes.i"
        INCLUDE "exec/lists.i"
        INCLUDE "exec/ports.i"
        INCLUDE "exec/libraries.i"
        INCLUDE "exec/tasks.i"
        INCLUDE "exec/memory.i"
        INCLUDE "exec/execbase.i"
        INCLUDE "libraries/dos.i"
        INCLUDE "libraries/dosextens.i"
        INCLUDE "workbench/startup.i"
        INCLUDE "exec/funcdef.i"
        INCLUDE "exec/exec_lib.i"
        INCLUDE "libraries/dos_lib.i"

MEMFLAGS EQU    MEMF_CLEAR+MEMF_PUBLIC
AbsExecBase EQU 4

; some usefull macros:

callsys macro
        CALLLIB _LVO\1
        endm
        
        xdef    XCEXIT                 * exit(code) is standard way to leave C.
	xdef 	@XCEXIT

        xref    LinkerDB               * linker defined base value
        xref    _BSSBAS                * linker defined base of BSS
        xref    _BSSLEN                * linker defined length of BSS
	IFD	RESIDENT
        xref        RESLEN
        xref        RESBASE
	xref	NEWDATAL
	ENDC
	
*       library references

        section text,code

        xref    _main                   * Name of C program to start with.
        xref    MemCleanup              * Free all allocated memory
        xref    __fpinit                * initialize floating point
        xref    __fpterm                * terminate floating point
	
start:
        move.l  a0,a2                  * save command pointer
        move.l  d0,d2                  * and command length
        lea     LinkerDB,a4            * load base register

	IFND	RESIDENT
        lea     _BSSBAS,a3             * get base of BSS
        moveq   #0,d1
        move.l  #_BSSLEN,d0            * get length of BSS in longwords
        bra.s   clr_lp                 * and clear for length given
clr_bss move.l  d1,(a3)+
clr_lp  dbf     d0,clr_bss
	ENDC
	
	IFD	RESIDENT
        move.l  AbsExecBase.W,a6

        movem.l     d0-d1/a0-a2,-(a7)
        sub.l         #RESBASE,a4
	move.l        #RESLEN,d0
        move.l        #MEMFLAGS,d1
        callsys       AllocMem
	tst.l	      d0
	beq.w	      abort
        move.l        d0,a0
        move.l        d0,a2
;a2 now has difference
        move.l        d0,a1
        move.l        #NEWDATAL,d0
;copy data over
cpy:    move.l        (a4)+,(a0)+
        subq.l        #1,d0
        bne           cpy
;a4 now points at number of relocs
        move.l        (a4)+,d0
reloc:  beq.s         nreloc
        move.l        a1,a0
        add.l         (a4)+,a0                   ;a0 now has add of reloc
        add.l         (a0),a2
        move.l        a2,(a0) 
        move.l        a1,a2	             ;restore offset
        subq.l        #1,d0
        bra.s         reloc
        
nreloc: move.l        a1,a4                        ; set up new base register
        add.l         #RESBASE,a4
        movem.l       (A7)+,d0-d1/a0-a2
	ENDC

        move.l  AbsExecBase.W,a6
        move.l  a6,SysBase(A4)
        move.l  a7,_StackPtr(A4)       * Save stack ptr
        clr.l   WBenchMsg(A4)

*------ get the address of our task
	move.l	ThisTask(a6),A3

*-----  clear any pending signals
	moveq	#0,d0
	move.l	#$00003000,d1
	callsys	SetSignal
	
*------ are we running as a son of Workbench?
        move.l  pr_CurrentDir(A3),curdir(A4)
        tst.l   pr_CLI(A3)
        beq     fromWorkbench

*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================
*
* Entry: D2 = command length
*        A2 = Command pointer
fromCLI:
        move.l  a7,D0           * get top of stack
        sub.l   4(a7),D0        * compute bottom 
        add.l   #128,D0         * allow for parms overflow
        move.l  D0,_base(A4)    * save for stack checking
*------ attempt to open DOS library:
        bsr.w     openDOS

*------ find command name:
        move.l  pr_CLI(a3),a0
        add.l   a0,a0           * bcpl pointer conversion
        add.l   a0,a0
        move.l  cli_CommandName(a0),a1
        add.l   a1,a1           * bcpl pointer conversion
        add.l   a1,a1

*------ collect parameters:
        move.l  d2,d0                   * get command line length
        moveq.l #0,d1
        move.b  (a1)+,d1
        move.l  a1,_ProgramName(A4)
        add.l   d1,d0                   * add length of command name
        addq.l  #1,d0                   * allow for space after command 

        clr.w   -(A7)                   * set null terminator for command line
        addq.l  #1,D0                   * force to even number of bytes
        andi.w  #$fffe,D0               *(round up)
        sub.l   D0,A7                   * make room on stack for command line
        subq.l  #2,D0
        clr.w   0(A7,D0)

*------ copy command line onto stack
        move.l  d2,d0                   * get command line length
        subq.l  #1,d0
        add.l   d1,d2

copy_line:
        move.b  0(A2,D0.W),0(A7,D2.W)   * copy command line to stack
        subq.l  #1,d2
        dbf     d0,copy_line
        move.b  #' ',0(a7,d2.w)         * add space between command and parms
        subq.l  #1,d2

copy_cmd:
        move.b  0(a1,d2.w),0(a7,d2.w)   * copy command name to stack
        dbf     d2,copy_cmd
        move.l  A7,A1
        move.l  A1,-(A7)                * push command line address
        bra     main                    * call C entrypoint

*=======================================================================
*====== Workbench Startup Code =========================================
*=======================================================================

fromWorkbench:

        move.l  TC_SPLOWER(a3),_base(A4) * set base of stack
	moveq   #127,d0
	addq.l	#1,d0                    * Efficient way of getting in 128
        add.l   d0,_base(A4)             * allow for parms overflow
*------ open the DOS library:
        bsr.w     openDOS

*------ we are now set up.  wait for a message from our starter
        lea     pr_MsgPort(A3),a0       * our process base
        callsys WaitPort
        lea     pr_MsgPort(A3),a0       * our process base
        callsys GetMsg
        move.l  d0,WBenchMsg(a4)
        move.l  d0,-(SP)
*
        move.l  d0,a2                   * get first argument
        move.l  sm_ArgList(a2),d0
        beq.s   do_cons
        move.l  DOSBase(a4),a6
        move.l  d0,a0
        move.l  wa_Lock(a0),d1
        move.l  d1,curdir(A4)
        callsys CurrentDir
do_cons:
        move.l  sm_ToolWindow(a2),d1    * get the window argument
        beq.s   do_main
        move.l  #MODE_OLDFILE,d2
        callsys Open
        move.l  d0,stdin(a4)
        beq.s   do_main
        lsl.l   #2,d0
        move.l  d0,a0
        move.l  fh_Type(a0),pr_ConsoleTask(A3)
do_main:
        move.l  WBenchMsg(A4),a0        * get address of workbench message
        move.l  a0,-(a7)                * push argv
        pea     NULL(a4)                * push argc
        move.l  sm_ArgList(a0),a0       * get address of arguments
        move.l  wa_Name(a0),_ProgramName(A4)       * get name of program

*=============================================
*------ common code --------
*=============================================

main    jsr     __fpinit(PC)            * Initialize floating point
        jsr     _main(PC)               * call C entrypoint
        moveq.l #0,d0                   * set successful status
        bra.s   exit2
*

XCEXIT:
        move.l  4(SP),d0                * extract return code
@XCEXIT:
exit2:
        move.l  d0,-(a7)
        move.l  _ONEXIT(A4),d0          * exit trap function?
        beq.s   exit3
        move.l  d0,a0
        jsr     (a0)
exit3   jsr     MemCleanup(PC)          * cleanup leftover memory alloc.
        move.l  AbsExecBase.W,a6
        move.l  DOSBase(A4),a1
        callsys CloseLibrary            * close Dos library

        jsr     __fpterm(PC)            * clean up any floating point

done_1c:
*------ if we ran from CLI, skip workbench cleanup:
        tst.l   WBenchMsg(A4)
        beq.s   exitToDOS
        move.l  stdin(a4),d1
        beq.s   done_4
        callsys Close
done_4:

*------ return the startup message to our parent
*       we forbid so workbench can't UnLoadSeg() us
*       before we are done:
        move.l  AbsExecBase.W,A6
        callsys Forbid
        move.l  WBenchMsg(a4),a1
        callsys ReplyMsg

*------ this rts sends us back to DOS:
exitToDOS:
	IFD	RESIDENT
	move.l	#RESLEN,d0
        move.l  a4,a1
        sub.l   #RESBASE,a1
        move.l  AbsExecBase.W,a6
        callsys FreeMem
	ENDC
	
        MOVE.L  (A7)+,D0
        movea.l _StackPtr(a4),SP        * restore stack ptr
        rts

	IFD	RESIDENT
abort:
        movem.l     (a7)+,d0-d1/a0-a2
	rts
	ENDC
	
*-----------------------------------------------------------------------
noDOS:
                moveq.l #100,d0
                bra     exit2



*-----------------------------------------------------------------------
*  Open the DOS library:

openDOS
                lea     DOSName(PC),A1
                moveq.l #0,D0
                callsys OpenLibrary
                move.l  D0,DOSBase(A4)
                beq     noDOS
                rts

DOSName         dc.b    'dos.library',0

        section __MERGED,BSS
*
        xref    DOSBase

        xdef    NULL,SysBase,WBenchMsg
        xdef    curdir,_mbase,_mnext,_msize,_tsize
        xdef    _oserr,_OSERR,_FPERR,_SIGFPE,_ONERR,_ONEXIT,_ONBREAK
        xdef    _SIGINT
        xdef    _ProgramName,_StackPtr,_base

*
NULL           ds.b    4               *
_base          ds.b    4               * base of stack
_mbase         ds.b    4               * base of memory pool
_mnext         ds.b    4               * next available memory location
_msize         ds.b    4               * size of memory pool
_tsize         ds.b    4               * total size?
_oserr         equ     *
_OSERR         ds.b    4
_FPERR         ds.b    4
_SIGFPE        ds.b    4
_SIGINT        ds.b    4
_ONERR         ds.b    4
_ONEXIT        ds.b    4
_ONBREAK       ds.b    4
curdir         ds.b    4
SysBase        ds.b    4
WBenchMsg      ds.b    4
_StackPtr      ds.b    4
stdin          ds.b    4
_ProgramName   ds.b    4
               END
