*:ts=8
****************************************************************************
*                                                                         *
* TINY.A                                 (C) Copyright Eddy Carroll 1989  *
* ~~~~~~                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
*                                                                         *
* Replacement startup code for Lattice C V5.04. Use instead of c.o        *
* This has many features stripped out to allow small utilities to have    *
* as small a filesize as possible. In particular, don't call any of the    *
* stdio functions.                                                        *
*                                                                         *
****************************************************************************

       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 "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"

MAXARGS            EQU 100     ; Maximum number of command line arguments from CLI
AbsExecBase EQU 4      ; Welcome to the only fixed point in the universe

* A useful macro to let us call library routines
callsys macro
       CALLLIB _LVO\1
       endm

       xdef    XCEXIT
       xdef    exit
       xref    LinkerDB
       xref    _BSSBAS
       xref    _BSSLEN

       csect   text,0,0,1,2            * xref's after this are 16-bit reloc
       xref    main                    * Name of C program to start with.

start:
       movem.l d1-d6/a0-a6,-(a7)
REGSIZE EQU    (6+7)*4
       lea     REGSIZE(a7),A5          * Determine old stack pointer
       move.l  a0,a2                   * Save command pointer
       move.l  d0,d2                   * and command length
       lea     LinkerDB,a4             * Load base register

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

       suba.l  a1,a1
       callsys FindTask                * Find out our task ID
       move.l  d0,a3

       move.l  a5,D0                   * get top of stack
       sub.l   4(a5),D0                * compute bottom
       add.l   #128,D0                 * allow for parms overflow
       move.l  D0,_base(A4)            * save for stack checking

       lea     DOSName(A4),A1
       moveq.l #0,D0
       callsys OpenLibrary
       move.l  D0,DOSBase(A4)
       bne     getcom
noDOS:
       moveq.l #100,d0
       bra     exit2

*------ find command name:
getcom:
       move.l  pr_CLI(a3),a0
       add.l   a0,a0
       add.l   a0,a0
       move.l  cli_CommandName(a0),a1
       add.l   a1,a1
       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                   * Get pointer to new command line

       sub.l   #(MAXARGS*4),a7         * Reserve space for argv[]
       move.l  a7,a2                   * Initialise base into array
       move.l  a2,a3                   * Save base of argv
       moveq   #0,d2                   * Initialise argc

*
* From here on down, A1 is pointer into command line
*
build_argv:
       bsr.s   getnext                 * Read next character from line
       bcs.s   doquote                 * If quote, handle
       beq.s   build_argv              * If white space, skip over it

       lea     -1(a1),a0               * Get address of this parameter
       bsr.s   bumpargv                * Store it to argv[] array
build_2:
       bsr.s   getnext                 * Get next character
       bne.s   build_2                 * If not white space, keep looking
       clr.b   -1(a1)                  * Zero-terminate current argument
       bra.s   build_argv              * And go back to get next argument

doquote:
       move.l  a1,a0                   * Get pointer to this argument
       bsr.s   bumpargv                * Output it to argv[]
quote_2:
       bsr.s   getnext                 * Get next character
       bcc.s   quote_2                 * If not quote, keep looking
       clr.b   -1(a1)                  * Zero-terminate current argument
quote_3:
       bsr.s   getnext                 * Get next character
       bne.s   quote_3                 * Skip until space reached
       beq.s   build_argv              * Go back and read next argument

bumpargv:
       move.l  a0,(a2)+                * Output ptr to current argument
       addq    #1,d2                   * Increment argc
       cmpi    #MAXARGS,d2             * Used up all our arguments yet?
       bls.s   qrts                    * If not, then return
       moveq   #110,d0                 * Else set return code
       bra.s   exit2                   * And exit

*
* Reads next character from command line. If zero, never returns, but
* drops into call to main. Else, returns, with C=1 if character is quote,
* Z=1 if character is white space.
*
getnext:
       move.b  (a1)+,d0                * Get character from command line
       beq.s   get_2                   * Exit if end of line
       cmp.b   #34,d0                  * Check if quote
       beq.s   isquote                 *
       cmp.b   #32,d0                  * Check if space
       beq.s   isspace                 *
       cmp.b   #9,d0                   * Or tab
       beq.s   isspace                 *
       cmp.b   #10,d0                  * Or end of line
isspace:
       andi    #$1E,ccr                * Clear carry flag, retaining Z
qrts   rts

isquote:
       ori     #1,ccr                  * Set carry flag
       andi    #$FB,ccr                * Clear zero flag
       rts                             * And return

get_2:
       move.l  a3,-(a7)                * Push argv onto stack
       move.l  d2,-(a7)                * Push argc onto stack

       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

domain:
       jsr     main(PC)                * Call main(argc,argv)
       moveq.l #0,d0                   * Set successful status
       bra.s   exit2

exit:
_exit:
XCEXIT:
       move.l  4(SP),d0                * Extract return code
exit2:
       move.l  d0,-(a7)
       move.l  AbsExecBase.W,a6
       move.l  DOSBase(A4),a1
       callsys CloseLibrary            * Close Dos library

*------ this rts sends us back to DOS:
exitToDOS:
       MOVE.L  (A7)+,D0
       movea.l _StackPtr(a4),SP        * Restore stack ptr
       movem.l (a7)+,d1-d6/a0-a6
       rts

*-----------------------------------------------------------------------
* Global definitions
*
       csect   __MERGED,1,,2,2

       xdef    NULL,SysBase,LoadAddress,DOSBase
       xdef    _oserr,_OSERR,_ONBREAK
       xdef    _ProgramName,_StackPtr,_base

NULL          dc.l    0
_base         dc.l    0
_oserr        equ     *
_OSERR        dc.l    0
_ONBREAK       dc.l    0
SysBase        dc.l    0
LoadAddress    dc.l    0
_StackPtr      dc.l    0
DOSBase        dc.l    0
_ProgramName   dc.l    0
DOSName        dc.b    'dos.library',0

       END
