*
* C initial startup procedure under AmigaDOS
* 

* Mode parameter to Open() 
MODE_OLDFILE         EQU   1005   * Open existing file read/write 
*                                 * positioned at beginning of file. 
MODE_NEWFILE         EQU   1006   * Open freshly created file (delete 
*                                 * old file) read/write            

	macro
	STRUCTURE	tag,offset
tag	set	0
soffset	set	offset
	endm

	macro
	BYTE	label
label	equ     soffset
soffset	set	soffset+1
	endm

	macro
	UBYTE	label
label	equ	soffset
soffset	set	soffset+1
	endm

	macro
	WORD	label
label	equ     soffset
soffset	set	soffset+2
	endm

	macro
	UWORD	label
label	equ	soffset
soffset	set	soffset+2
	endm

	macro
	SHORT	label
label	equ	soffset
soffset	set	soffset+2
	endm

	macro
	USHORT	label
label	equ	soffset
soffset	set	soffset+2
	endm

	macro
	LONG	label
label	equ	soffset
soffset	set	soffset+4
	endm

	macro
	ULONG	label
label	equ	soffset
soffset	set	soffset+4
	endm

	macro
	APTR	label
label	equ	soffset
soffset	set	soffset+4
	endm

	macro
	BPTR	label
label	equ	soffset
soffset	set	soffset+4
	endm

	macro
	BSTR	label
label	equ	soffset
soffset	set	soffset+4
	endm

	macro
	RPTR	label
label	equ	soffset
soffset	set	soffset+2
	endm

	macro
	STRUCT	label,size
label	equ	soffset
soffset	set	soffset+size
	endm

	macro
	LABEL	label
label	equ	soffset
	endm

*---------------------------------------------------------------------
*
*   List Structures
*
*---------------------------------------------------------------------

 STRUCTURE  LH,0
    APTR    LH_HEAD
    APTR    LH_TAIL
    APTR    LH_TAILPRED
    UBYTE   LH_TYPE
    UBYTE   LH_pad
    LABEL   LH_SIZE

*----------------------------------------------------------------
*
*   List Node Structure
*
*----------------------------------------------------------------

 STRUCTURE  LN,0
    APTR    LN_SUCC
    APTR    LN_PRED
    UBYTE   LN_TYPE
    BYTE    LN_PRI
    APTR    LN_NAME
    LABEL   LN_SIZE

*----------------------------------------------------------------
*
*   Message Port Structure
*
*----------------------------------------------------------------

 STRUCTURE  MP,LN_SIZE
    UBYTE   MP_FLAGS
    UBYTE   MP_SIGBIT               * signal bit number
    APTR    MP_SIGTASK              * task to be signalled
    STRUCT  MP_MSGLIST,LH_SIZE      * message linked list
    LABEL   MP_SIZE

*----------------------------------------------------------------
*
*   Message Structure
*
*----------------------------------------------------------------

 STRUCTURE  MN,LN_SIZE
    APTR    MN_REPLYPORT            * message reply port
    UWORD   MN_LENGTH               * message len in bytes
    LABEL   MN_SIZE


 STRUCTURE WBStartup,0
    STRUCT  sm_Message,MN_SIZE      ; a standard message structure
    APTR    sm_Process              ; the process descriptor for you
    BPTR    sm_Segment              ; a descriptor for your code
    LONG    sm_NumArgs              ; the number of elements in ArgList
    APTR    sm_ToolWindow           ; description of window
    APTR    sm_ArgList              ; the arguments themselves
    LABEL   sm_SIZEOF

 STRUCTURE WBArg,0
    BPTR    wa_Lock                 ; a lock descriptor
    APTR    wa_Name                 ; a string relative to that lock
    LABEL   wa_SIZEOF

* The long word address (BPTR) of this STRUCTure is returned by
* Open() and other routines that return a file.  You need only worry
* about this STRUCT to do async io's via PutMsg() instead of
* standard file system calls

 STRUCTURE FileHandle,0
   APTR   fh_Link          * pointer to EXEC message
   APTR   fh_Interactive   * Boolean; TRUE if interactive handle
   APTR   fh_Type          * Port to do PutMsg() to
   LONG   fh_Buf
   LONG   fh_Pos
   LONG   fh_End
   LONG   fh_Funcs
fh_Func1 EQU fh_Funcs
   LONG   fh_Func2
   LONG   fh_Func3
   LONG   fh_Args
fh_Arg1 EQU fh_Args
   LONG   fh_Arg2
   LABEL  fh_SIZEOF * FileHandle

*----------------------------------------------------------------
*
*   Task Control Structure
*
*----------------------------------------------------------------

 STRUCTURE  TC,LN_SIZE
    UBYTE   TC_FLAGS
    UBYTE   TC_STATE
    BYTE    TC_IDNESTCNT            * intr disabled nesting
    BYTE    TC_TDNESTCNT            * task disabled nesting
    ULONG   TC_SIGALLOC             * sigs allocated
    ULONG   TC_SIGWAIT              * sigs we are waiting for
    ULONG   TC_SIGRECVD             * sigs we have received
    ULONG   TC_SIGEXCEPT            * sigs we take as exceptions
    UWORD   TC_TRAPALLOC            * traps allocated
    UWORD   TC_TRAPABLE             * traps enabled
    APTR    TC_EXCEPTDATA           * data for except proc
    APTR    TC_EXCEPTCODE           * exception procedure
    APTR    TC_TRAPDATA             * data for proc trap proc
    APTR    TC_TRAPCODE             * proc trap procedure
    APTR    TC_SPREG                * stack pointer
    APTR    TC_SPLOWER              * stack lower bound
    APTR    TC_SPUPPER              * stack upper bound + 2
    APTR    TC_SWITCH               * task losing CPU
    APTR    TC_LAUNCH               * task getting CPU
    STRUCT  TC_MEMENTRY,LH_SIZE     * allocated memory
    APTR    TC_Userdata
    LABEL   TC_SIZE

* All DOS processes have this STRUCTure
* Create and DeviceProc returns pointer to the MsgPort in this STRUCTure
* Process_addr = DeviceProc(..) - TC_SIZE

 STRUCTURE Process,0
    STRUCT  pr_Task,TC_SIZE
    STRUCT  pr_MsgPort,MP_SIZE  * This is BPTR address from DOS functions
    WORD    pr_Pad              * Remaining variables on 4 byte boundaries
    BPTR    pr_SegList          * Array of seg lists used by this process
    LONG    pr_StackSize        * Size of process stack in bytes
    APTR    pr_GlobVec          * Global vector for this process (BCPL)
    LONG    pr_TaskNum          * CLI task number of zero if not a CLI
    BPTR    pr_StackBase        * Ptr to high memory end of process stack
    LONG    pr_Result2          * Value of secondary result from last call
    BPTR    pr_CurrentDir       * Lock associated with current directory
    BPTR    pr_CIS              * Current CLI Input Stream
    BPTR    pr_COS              * Current CLI Output Stream
    APTR    pr_ConsoleTask      * Console handler process for current window
    APTR    pr_FileSystemTask   * File handler process for current drive
    BPTR    pr_CLI              * pointer to ConsoleLineInterpreter
    APTR    pr_ReturnAddr       * pointer to previous stack frame
    APTR    pr_PktWait          * Function to be called when awaiting msg
    APTR    pr_WindowPtr        * Window pointer for errors
    LABEL   pr_SIZEOF           * Process

* DOS Processes started from the CLI via RUN or NEWCLI have this additional
* set to data associated with them

 STRUCTURE CommandLineInterface,0
    LONG   cli_Result2         * Value of IoErr from last command
    BSTR   cli_SetName         * Name of current directory
    BPTR   cli_CommandDir      * Lock associated with command directory
    LONG   cli_ReturnCode      * Return code from last command
    BSTR   cli_CommandName     * Name of current command
    LONG   cli_FailLevel       * Fail level (set by FAILAT)
    BSTR   cli_Prompt          * Current prompt (set by PROMPT)
    BPTR   cli_StandardInput   * Default (terminal) CLI input
    BPTR   cli_CurrentInput    * Current CLI input
    BSTR   cli_CommandFile     * Name of EXECUTE command file
    LONG   cli_Interactive     * Boolean True if prompts required
    LONG   cli_Background      * Boolean True if CLI created by RUN
    BPTR   cli_CurrentOutput   * Current CLI output
    LONG   cli_DefaultStack    * Stack size to be obtained in long words
    BPTR   cli_StandardOutput  * Default (terminal) CLI output
    BPTR   cli_Module          * SegList of currently loaded command
    LABEL  cli_SIZEOF          * CommandLineInterface

	xdef	_XCEXIT			* exit(code) is standard way to leave C.

	xref	_LinkerDB		* linker defined base value
	xref	__BSSBAS		* linker defined base of BSS
	xref	__BSSLEN		* linker defined length of BSS

	xref	_Debug
	xref	__main			* Name of C program to start with.
	xref	_MemCleanup
	xref	_AbsExecBase
	xref	_FindTask
	xref	_DOSBase
	xref	_MathBase
	xref	_MathTransBase

*	library references

	csect	text,0,0,1,2	* any xref's after this are 16-bit reloc

	xref	_LVOAlert
	xref	_LVOFindTask
	xref	_LVOForbid
	xref	_LVOGetMsg
	xref	_LVOOpenLibrary
	xref	_LVOCloseLibrary
	xref	_LVOReplyMsg
	xref	_LVOWait
	xref	_LVOWaitPort
	xref	_LVOOpen
	xref	_LVOClose
	xref	_LVOCurrentDir

start:
	move.l	d0,dosCmdLen
	move.l	a0,dosCmdBuf
	move.l	a7,d0			* save old stack ptr
	movem.l	d1-d6/a0-a6,-(a7)
	move.l	d0,a5
	move.l	_AbsExecBase,a6
	move.l	a6,_SysBase
	move.l	a7,__StackPtr		* Save stack ptr
	clr.l	_WBenchMsg

*------ get the address of our task
	suba.l	a1,a1
	jsr	 _LVOFindTask(a6)
	move.l	d0,a4

*------ are we running as a son of Workbench?
	move.l	pr_CurrentDir(A4),_curdir
	tst.l	pr_CLI(A4)
	beq	fromWorkbench

*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================

fromCLI:
	move.l	a5,D0		* get top of stack
	sub.l	4(a5),D0	* compute bottom 
	move.l	D0,__base	* save for stack checking
*------	attempt to open DOS library:
	bsr	openDOS

*------ find command name:
	clr.l	-(sp)
	jsr	_FindTask
	addq.l	#4,sp
	move.l	d0,a0
	move.l	pr_CLI(a0),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	dosCmdLen,d0		* get command line length
	moveq.l	#0,d1
	move.b	(a1)+,d1
	move.l	a1,__ProgramName
	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	dosCmdLen,d0		* get command line length
	move.l	dosCmdBuf,a0
	move.l	d0,d2
	subq.l	#1,d0
	add.l	d1,d2

copy_line:
	move.b	0(A0,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	goto_main		        * call C entrypoint

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

fromWorkbench:

	move.l	TC_SPLOWER(a4),__base	* set base of stack
*------ open the DOS library:
	bsr	openDOS

*------ we are now set up.  wait for a message from our starter
	bsr	waitmsg
	move.l	d0,_WBenchMsg
	move.l	d0,-(SP)
*
	move.l	d0,a2			* get first argument
	move.l	sm_ArgList(a2),d0
	beq.s	do_cons
	move.l	_DOSBase,a6
	move.l	d0,a0
	move.l	wa_Lock(a0),d1
	move.l	d1,_curdir
	jsr	_LVOCurrentDir(a6)
do_cons:TE   LaceWB;
    UBYTE   WorkName[FILENAME_SIZE];
    BYTE    RowSizeChange;
    BYTE    ColumnSizeChange;
    BYTE    padding[14];
};
#define LACEWB 0x01
#define PARALLEL_PRINTER 0x00
#define SERIAL_PRINTER  0x01
#define BAUD_110        0x00
#define BAUD_300        0x01
#define BAUD_1200       0x02
#define BAUD_2400       0x03
#define BAUD_4800       0x04
#define BAUD_9600       0x05
#define BAUD_19200      0x06
#define BAUD_MIDI       0x07
#define FANFOLD         0x00
#define SINGLE          0x80
#define PICA            0x000
#define ELITE           0x400
#define FINE            0x800
#define DRAFT           0x000
#define LETTER          0x100
#define SIX_LPI         0x000
#define EIGHT_LPI       0x200
#define IMAGE_POSITIVE  0x00
#define IMAGE_NEGATIVE  0x01
#define ASPECT_HORIZ    0x00
#define ASPECT_VERT     0x01
#define SHADE_BW        0x00
#define SHADE_GREYSCALE 0x01
#define SHADE_COLOR     0x02
#define US_LETTER       0x00
#define US_LEGAL        0x10
#define N_TRACTOR       0x20
#define W_TRACTOR       0x30
#define CUSTOM          0x40
#define CUSTOM_NAME             0x00
#define ALPHA_P_101             0x01
#define BROTHER_15XL            0x02
#define CBM_MPS1000             0x03
#define DIAB_630                0x04
#define DIAB_ADV_D25            0x05
#define DIAB_C_150              0x06
#define EPSON                   0x07
#define EPSON_JX_80             0x08
#define OKIMATE_20              0x09
#define QUME_LP_20              0x0A
#define HP_LASERJET             0x0B
#define HP_LASERJET_PLUS        0x0C
#define SBUF_512        0x00
#define SBUF_1024       0x01
#define SBUF_2048       0x02
#define SBUF_4096       0x03
#define SBUF_8000       0x04
#define SBUF_16000      0x05
#define SREAD_BITS      0xF0
#define SWRITE_BITS     0x0F
#define SSTOP_BITS      0xF0
#define SBUFSIZE_BITS   0x0F
#define SPARITY_BITS    0xF0
#define SPARITY_NONE     0
#define SPARITY_EVEN     1
#define SPARITY_ODD      2
#define SHSHAKE_XON      0
#define SHSHAKE_RTS      1
#define SHSHAKE_NONE     2
struct Remember
{
    struct Remember *NextRemember;
    ULONG RememberSize;
    UBYTE *Memory;
};
#define MENUNUM(n) (n & 0x1F)
#define ITEMNUM(n) ((n >> 5) & 0x003F)
#define SUBNUM(n) ((n >> 11) & 0x001F)
#define SHIFTMENU(n) (n & 0x1F)
#define SHIFTITEM(n) ((n & 0x3F) << 5)
#define SHIFTSUB(n) ((n & 0x1F) << 11)
#define SRBNUM(n)    (0x08 - (n >> 4))
#define SWBNUM(n)    (0x08 - (n & 0x0F))
#define SSBNUM(n)    (0x01 + (n >> 4))
#define SPARNUM(n)   (n >> 4)
#define SHAKNUM(n)   (n & 0x0F)
#define NOMENU 0x001F
#define NOITEM 0x003F
#define NOSUB  0x001F
#define MENUNULL 0xFFFF
#define FOREVER for(;;)
#define SIGN(x) ( ((x) > 0) - ((x) < 0) )
#define NOT !
#define CHECKWIDTH      19
#define COMMWIDTH       27
#define LOWCHECKWIDTH   13
#define LOWCOMMWIDTH    16
#define ALERT_TYPE      0x80000000
#define RECOVERY_ALERT  0x00000000
#define DEADEND_ALERT   0x80000000
#define AUTOFRONTPEN    0
#define AUTOBACKPEN     1
#define AUTODRAWMODE    JAM2
#define AUTOLEFTEDGE    6
#define AUTOTOPEDGE     3
#define AUTOITEXTFONT   NULL
#define AUTONEXTTEXT    NULL
#define SELECTUP        (IECODE_LBUTTON | IECODE_UP_PREFIX)
#define SELECTDOWN      (IECODE_LBUTTON)
#define MENUUP          (IECODE_RBUTTON | IECODE_UP_PREFIX)
#define MENUDOWN        (IECODE_RBUTTON)
#define ALTLEFT         (IEQUALIFIER_LALT)
#define ALTRIGHT        (IEQUALIFIER_RALT)
#define AMIGALEFT       (IEQUALIFIER_LCOMMAND)
#define AMIGARIGHT      (IEQUALIFIER_RCOMMAND)
#define AMIGAKEYS       (AMIGALEFT | AMIGARIGHT)
#define CURSORUP        0x4C
#define CURSORLEFT      0x4F
#define CURSORRIGHT     0x4E
#define CURSORDOWN      0x4D
#define KEYCODE_Q       0x10
#define KEYCODE_X       0