home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 3
/
goldfish_volume_3.bin
/
files
/
cbm
/
nduk
/
nduk-v37
/
startups
/
startup.asm
< prev
next >
Wrap
Assembly Source File
|
1991-11-11
|
27KB
|
800 lines
*------ startup.asm v 36.13
*
* Copyright (c) 1990 Commodore-Amiga, Inc.
*
*
*------
*------ Conditional assembly flags
*------ ASTART: 1=Standard Globals Defined 0=Reentrant Only
*------ WINDOW: 1=AppWindow for WB startup 0=No AppWindow code
*------ XNIL: 1=Remove startup NIL: init 0=Default Nil: WB Output
*------ NARGS: 1=Argv[0] only 0=Normal cmd line arg parse
*------ DEBUG: 1=Set up old statics for Wack 0=No extra statics
*------ QARG: 1=No argv 0=Passes argc,argv
* Include the appropriate startup.i (example rstartup.i) here or in
* your assem line
INCLUDE "allstartup.i"
* Flags for [A]start AWstart Rstart RWstart RXstart QStart
* ASTART 1 1 0 0 0 0
* WINDOW 0 1 0 1 0 0
* XNIL 0 0 0 0 1 1
* NARGS 0 0 0 0 0 0
* DEBUG 0 0 0 0 0 0
* QARG 0 0 0 0 0 1
;------ Flag WB output initialization
NNIL SET (1-XNIL)
WBOUT SET (ASTART!WINDOW!NNIL)
************************************************************************
*
* startup.asm --- Reentrant C Program Startup/Exit (CLI and WB)
* v36.13 011/07/90
*
* Copyright (c) 1988, 1990 Commodore-Amiga, Inc.
*
* Title to this software and all copies thereof remain vested in the
* authors indicated in the above copyright notice. The object version
* of this code may be used in software for Commodore Amiga computers.
* All other rights are reserved.
*
* NO REPRESENTATIONS OR WARRANTIES ARE MADE WITH RESPECT TO THE
* ACCURACY, RELIABILITY, PERFORMANCE OR OPERATION OF THIS SOFTWARE,
* AND ALL SUCH USE IS AT YOUR OWN RISK. NEITHER COMMODORE NOR THE
* AUTHORS ASSUME ANY RESPONSIBILITY OR LIABILITY WHATSOEVER WITH
* RESPECT TO YOUR USE OF THIS SOFTWARE.
*
*
* RSTARTUP.ASM
*
* Changes for 2.0 - since commands may now receive a >256 character command
* line, the argv buffer size is now dynamic, based on DosCmdLen passed in.
* The argv count is also dynamic, based on number of spaces in the command
* line.
*
* This startup dynamically allocates a structure which includes
* the argv buffers. If you use this startup, your code must return
* to this startup when it exits. Use exit(n) or final curly brace
* (rts) to return here. Do not use AmigaDOS Exit( ) function.
* Due to this dynamic allocation and some code consolidation, this
* startup can make executables several hundred bytes smaller.
*
* Because a static initialSP variable can not be used, this
* code depends on the fact that AmigaDOS places the address of
* the top of our stack in SP and proc->pr_ReturnAddr right before
* JSR'ing to us. This code uses pr_ReturnAddr when restoring SP.
*
* Most versions of startup will initialize a Workbench process's
* input and output streams (and stdio globals if present) to NIL:
* if no other form of Workbench output (like WINDOW) is provided.
* This should help prevent crashes if a user puts an icon on a CLI
* program, and will also protect against careless stdio debugging
* or error messages left in a Workbench program. The code for
* initializing Workbench IO streams only be removed by assembling
* startup with ASTART and WINDOW set to 0, and XNIL set to 1.
*
*
* Some startups which can be conditionally assembled:
*
* 1. Standard Astartup for non-reentrant code
* 2. Reentrant Rstartup (no unshareable globals)
* 3. Smaller reentrant-only RXstartup (no NIL: WB init code)
* 4. Standard AWstartup (WB output window) for non-reentrant code
* 5. Reentrant RWstartup (WB output window, no unshareable globals)
* 6. Smallest Qstartup (No argv - argv is ptr to NULL string)
*
*
* Explanation of conditional assembly flags:
*
* ASTART (ASTART SET 1) startups will set up and XDEF the
* global variables _stdin, _stdout, _stderr, _errno and _WBenchMsg.
* These startups can be used as smaller replacements for startups
* like (A)startup.obj and TWstartup.obj. Startups with ASTART
* would generally be used for non-reentrant programs, although the
* startup code itself is still reentrant if the globals are not
* referenced.
* Reentrant (ASTART SET 0) startups will NOT set up or
* XDEF the stdio and WBenchMsg globals. This not only makes the
* startup slightly smaller, but also lets you know if your code
* is referencing these non-reentrant globals (you will get an
* unresolved external reference when you link). Programs
* get their input and output handles from Input( ) and Output( ),
* and the WBenchMsg is passed in argv on Workbench startup.
*
* WINDOW (WINDOW SET 1) startups use an XREF'd CON: string
* named AppWindow, defined in your application, to open a stdio
* console window when your application is started from Workbench.
* For non-reentrant programs, this window can be used for normal
* stdio (printf, getchar, etc). For reentrant programs the window
* is Input( ) and Output( ). WINDOW is useful when adding Workbench
* capability to a stdio application, and also for debugging other
* Workbench applications. To insure that applications requiring
* a window startup are linked with a window startup, the label
* _NeedWStartup can be externed and referenced in the application
* so that a linker error will occur if linked with a standard
* startup.
*
* example: /* Optional safety reference to NeedWStartup */
* extern UBYTE NeedWStartup;
* UBYTE *HaveWStartup = &NeedWStartup;
* /* Required window specification */
* char AppWindow[] = "CON:30/30/200/150/MyProgram";
* ( OR char AppWindow[] = "\0"; for no window )
*
*
* XNIL (XNIL SET 1) allows the creation of a smaller startup
* by removing the code that initializes a Workbench process's
* output streams to NIL:. This flag can only remove the code
* if it is not required for ASTART or WINDOW.
*
* NARGS (NARGS SET 1) removes the code used to parse command line
* arguments. The command name is still passed to _main as argv[0].
* This option can take about 120 bytes off the size of any program that
* does not use command line args.
*
* DEBUG (DEBUG SET 1) will cause the old startup.asm statics
* initialSP, dosCmdLen and dosCmdBuf to be defined and initialized
* by the startup code, for use as debugging symbols when using Wack.
*
* QARG (QARG SET TO 1) will bypass all argument parsing. A CLI
* startup is passed argc == 1, and a Workbench startup is passed
* argc == 0. Argv[0] will be a pointer to a NULL string rather than
* a pointer to the command name. This option creates a very small
* startup with no sVar structure allocation, and therefore must be used
* with XNIL (it is incompatible with default or AWindow output options).
*
*
* RULES FOR REENTRANT CODE
*
* - Make no direct or indirect (printf, etc) references to the
* globals _stdin, _stdout, _stderr, _errno, or _WBenchMsg.
*
* - For stdio use either special versions of printf and getchar
* that use Input( ) and Output( ) rather than _stdin and _stdout,
* or use fprintf and fgetc with Input( ) and Output( ) file handles.
*
* - Workbench applications must get the pointer to the WBenchMsg
* from argv rather than from a global extern WBenchMsg.
*
* - Use no global or static variables within your code. Instead,
* put all former globals in a dynamically allocated structure, and
* pass around a pointer to that structure. The only acceptable
* globals are constants (message strings, etc) and global copies
* of Library Bases to resolve Amiga.lib references. Your code
* must return all OpenLibrary's into non-global variables,
* copy the result to the global library base only if successful,
* and use the non-globals when deciding whether to Close any
* opened libraries.
*
************************************************************************
******* Included Files *************************************************
INCLUDE "exec/types.i"
INCLUDE "exec/alerts.i"
INCLUDE "exec/memory.i"
INCLUDE "libraries/dos.i"
INCLUDE "libraries/dosextens.i"
INCLUDE "workbench/startup.i"
******* MACROS *********************************************************
CODE
xlib macro
xref _LVO\1
endm
callsys macro
CALLLIB _LVO\1
endm
******* Imported *******************************************************
ABSEXECBASE EQU 4
xref _main ; C code entry point
IFGT WINDOW
xref _AppWindow ; CON: spec in application for WB stdio window
xdef _NeedWStartup ; May be externed and referenced in application
ENDC WINDOW
xlib Alert
xlib AllocMem
xlib FindTask
xlib Forbid
xlib FreeMem
xlib GetMsg
xlib OpenLibrary
xlib CloseLibrary
xlib ReplyMsg
xlib Wait
xlib WaitPort
xlib CurrentDir
xlib Open
xlib Close
xlib Input
xlib Output
******* Exported *******************************************************
*----- These globals are set up for standard startup code only
IFGT ASTART
xdef _stdin
xdef _stdout
xdef _stderr
xdef _errno
xdef _WBenchMsg
ENDC ASTART
*----- These globals available to normal and reentrant code
xdef _SysBase
xdef _DOSBase
xdef _exit ; standard C exit function
***** Startup Variables structure **********************************
IFEQ QARG
; NOTE - the ArgvArray must be last
; It and the ArgvBuffer which follow it are dynamically sized/allocated (2.0)
STRUCTURE SVar,0
ULONG sv_Size
LONG sv_WbOutput
ULONG sv_ArgvBufPtr
ULONG sv_MaxArgc
LABEL sv_ArgvArray
LABEL SV_SIZEOF
ENDC QARG
************************************************************************
* Standard Program Entry Point
************************************************************************
*
* Entered with
* d0 dosCmdLen
* a0 dosCmdBuf
* Any registers (except sp) are allowed to be modified
*
* Calls
* main (argc, argv)
* int argc;
* char *argv[];
*
* For Workbench startup, argc=0, argv=WBenchMsg
*
************************************************************************
startup:
IFGT DEBUG
move.l sp,initialSP
move.l d0,dosCmdLen
move.l a0,dosCmdBuf
ENDC DEBUG
IFEQ QARG
move.l d0,d2
move.l a0,a2
ENDC QARG
;------ get Exec library base pointer
movea.l ABSEXECBASE,a6
move.l a6,_SysBase
;------ get the address of our task
suba.l a1,a1 ; clear a1
callsys FindTask
move.l d0,a4 ; keep task address in a4
;------ get DOS library base pointer
moveq #0,d0
lea DOSName(pc),A1 ; dos.library
callsys OpenLibrary
tst.l d0
beq alertDOS ; fail on null with alert
move.l d0,_DOSBase ; Else set the global
IFEQ QARG
;------ branch over argv calculations if not a CLI process
move.l pr_CLI(A4),d0
bne.s vcnt
moveq #2,d4 ; if wb startup alloc 2 argv's
moveq #8,d2 ; fake dos cmd line size for alloc
bra.s wbnoargs
vcnt:
;------ estimate max number of argv's for CLI command line
;------ command + number spaces + 1 + null argv
movea.l a2,a0 ; dos command line
moveq #3,d4 ; start count at 3, add spaces
vcnt1:
cmp.b #' ',(a0)
bne.s vcnt2
addq #1,d4
vcnt2:
tst.b (a0)+
bne.s vcnt1
;------ branch to here has d4=2, d2=8 for wb startup
wbnoargs:
;------ d4 now equals at least max number argv's needed
move.l d4,d0
lsl.l #2,d0 ; convert to bytes needed for argv ptrs
move.l d0,d5 ; save in d5
add.l d2,d0 ; add dos command line size for buffer
add.l #SV_SIZEOF+1,d0 ; add structure size + 1 for null term
;------ alloc the argument structure
move.l d0,d3 ; save total size for de-allocation
move.l #(MEMF_PUBLIC!MEMF_CLEAR),d1
callsys AllocMem
tst.l d0
beq alertMem ; fail on null with alert
move.l d0,-(sp) ; save sVar ptr on stack
move.l d0,a5 ; sVar ptr to a5
move.l d3,sv_Size(a5) ; size for de-allocation later (2.0)
subq.l #1,d4
move.l d4,sv_MaxArgc(a5) ; max argc
lea.l sv_ArgvArray(a5),a0
adda.l d5,a0
move.l a0,sv_ArgvBufPtr(a5)
ENDC QARG
IFGT QARG
clr.l -(sp)
ENDC QARG
clr.l -(sp) ; reserve space for WBenchMsg if any
;------ branch to Workbench startup code if not a CLI process
move.l pr_CLI(A4),d0
beq fromWorkbench
;=======================================================================
;====== CLI Startup Code ===============================================
;=======================================================================
; d0 process CLI BPTR (passed in), then temporary
; d2 dos command length (passed in)
; d3 argument count
; a0 temporary
; a1 argv buffer
; a2 dos command buffer (passed in)
; a3 argv array
; a4 Task (passed in)
; a5 SVar structure if not QARG (passed in)
; a6 AbsExecBase (passed in)
; sp WBenchMsg (still 0), sVar or 0, then RetAddr (passed in)
; sp argc, argv, WBenchMsg, sVar or 0,RetAddr (at bra domain)
IFEQ QARG
;------ find command name
lsl.l #2,d0 ; pr_CLI bcpl pointer conversion
move.l d0,a0
move.l cli_CommandName(a0),d0
lsl.l #2,d0 ; bcpl pointer conversion
;-- start argv array
move.l sv_ArgvBufPtr(a5),a1
lea sv_ArgvArray(a5),a3
;-- copy command name
move.l d0,a0
moveq.l #0,d0
move.b (a0)+,d0 ; size of command name
clr.b 0(a0,d0.l) ; terminate the command name
move.l a0,(a3)+
moveq #1,d3 ; start counting arguments
IFEQ NARGS
;------ null terminate the arguments, eat trailing control characters
lea 0(a2,d2.l),a0
stripjunk:
cmp.b #' ',-(a0)
dbhi d2,stripjunk
clr.b 1(a0)
;------ start gathering arguments into buffer
newarg:
;-- skip spaces
move.b (a2)+,d1
beq.s parmExit
cmp.b #' ',d1
beq.s newarg
cmp.b #9,d1 ; tab
beq.s newarg
;-- check for argument count overflow
cmp.l sv_MaxArgc(a5),d3
beq.s parmExit
;-- push address of the next parameter
move.l a1,(a3)+
addq.w #1,d3
;-- process quotes
cmp.b #'"',d1
beq.s doquote
;-- copy the parameter in
move.b d1,(a1)+
nextchar:
;------ null termination check
move.b (a2)+,d1
beq.s parmExit
cmp.b #' ',d1
beq.s endarg
move.b d1,(a1)+
bra.s nextchar
endarg:
clr.b (a1)+
bra.s newarg
doquote:
;------ process quoted strings
move.b (a2)+,d1
beq.s parmExit
cmp.b #'"',d1
beq.s endarg
;-- '*' is the BCPL escape character
cmp.b #'*',d1
bne.s addquotechar
move.b (a2)+,d1
move.b d1,d2
and.b #$df,d2 ;d2 is temp toupper'd d1
cmp.b #'N',d2 ;check for dos newline char
bne.s checkEscape
;-- got a *N -- turn into a newline
moveq #10,d1
bra.s addquotechar
checkEscape:
cmp.b #'E',d2
bne.s addquotechar
;-- got a *E -- turn into a escape
moveq #27,d1
addquotechar:
move.b d1,(a1)+
bra.s doquote
parmExit:
;------ all done -- null terminate the arguments
clr.b (a1)
clr.l (a3)
ENDC NARGS
pea sv_ArgvArray(a5) ; argv
move.l d3,-(sp) ; argc
ENDC QARG
IFGT QARG
pea nullArgV(pc) ; pointer to pointer to null string
pea 1 ; only one pointer
ENDC
IFGT ASTART
movea.l _DOSBase,a6
;------ get standard input handle:
callsys Input
move.l d0,_stdin
;------ get standard output handle:
callsys Output
move.l d0,_stdout
move.l d0,_stderr
movea.l ABSEXECBASE,a6
ENDC ASTART
bra domain
;=======================================================================
;====== Workbench Startup Code =========================================
;=======================================================================
; a2 WBenchMsg
; a4 Task (passed in)
; a5 SVar structure if not QARG (passed in)
; a6 AbsExecBase (passed in)
; sp WBenchMsg (still 0), sVar or 0, then RetAddr (passed in)
; sp argc=0,argv=WBenchMsg,WBenchMsg,sVar or 0,RetAddr (at domain)
fromWorkbench:
;------ get the startup message that workbench will send to us.
; must get this message before doing any DOS calls
bsr.s getWbMsg
;------ save the message so we can return it later
move.l d0,(sp)
IFGT ASTART
move.l d0,_WBenchMsg
ENDC ASTART
;------ push the message on the stack for wbmain (as argv)
move.l d0,-(sp)
clr.l -(sp) ; indicate run from Workbench (argc=0)
IFNE (1-QARG)+WBOUT
;------ put DOSBase in a6 for next few calls
move.l _DOSBase,a6
ENDC (1-QARG)+WBOUT
IFEQ QARG
;------ get the first argument
move.l d0,a2
move.l sm_ArgList(a2),d0
beq.s doCons
;------ and set the current directory to the same directory
move.l d0,a0
move.l wa_Lock(a0),d1
;should be a beq.s doCons here
callsys CurrentDir
doCons:
ENDC QARG
IFGT WBOUT
;------ Open NIL: or AppWindow for WB Input()/Output() handle
; Also for possible initialization of stdio globals
; Stdio used to be initialized to -1
IFGT WINDOW
;------ Get AppWindow defined in application
lea _AppWindow,a0
cmp.b #0,(a0)
bne.s doOpen ; Open if not null string
ENDC WINDOW
;------ Open NIL: if no window provided
lea NilName(PC),a0
doOpen:
;------ Open up the file whose name is in a0
; DOSBase still in a6
move.l a0,d1
move.l #MODE_OLDFILE,d2
callsys Open
;------ d0 now contains handle for Workbench Output
;------ save handle for closing on exit
move.l d0,sv_WbOutput(a5)
bne.s gotOpen
moveq.l #RETURN_FAIL,d2
bra exit2
gotOpen:
IFGT ASTART
;------ set the C input and output descriptors
move.l d0,_stdin
move.l d0,_stdout
move.l d0,_stderr
ENDC ASTART
;------ set the console task (so Open( "*", mode ) will work
; task pointer still in A4
move.l d0,pr_CIS(A4)
move.l d0,pr_COS(A4)
lsl.l #2,d0
move.l d0,a0
move.l fh_Type(a0),d0
beq.s noConTask
move.l d0,pr_ConsoleTask(A4)
noConTask:
ENDC WBOUT
;------ Fall though to common WB/CLI code
****************************************************
** This code now used by both CLI and WB startup **
****************************************************
domain:
jsr _main
;------ main didn't use exit(n) so provide success return code
moveq.l #RETURN_OK,d2
bra.s exit2
****************************************************
** subroutines here to allow short branches **
****************************************************
getWbMsg:
;------ a6 = ExecBase
lea pr_MsgPort(A4),a0 ; our process base
callsys WaitPort
lea pr_MsgPort(A4),a0 ; our process base
callsys GetMsg
rts
****************************************************
alertDOS:
;------ do recoverable alert for no DOS and exit
ALERT (AG_OpenLib!AO_DOSLib)
;------ do recoverable alert for no memory and exit
;------ If we got this far, DOS is open, so close it
IFEQ QARG
bra.s failExit
alertMem:
movea.l _DOSBase,a1
callsys CloseLibrary
ALERT AG_NoMemory
ENDC QARG
failExit:
tst.l pr_CLI(a4)
bne.s fail2
bsr.s getWbMsg
movea.l d0,a2
bsr.s repWbMsg
fail2:
moveq.l #RETURN_FAIL,d0
rts
****************************************************
repWbMsg:
;------ return the startup message to our parent
; a6 = ExecBase (passed)
; a2 = WBenchMsg (passed)
; we forbid so workbench can't UnLoadSeg() us before we are done
callsys Forbid
move.l a2,a1
callsys ReplyMsg
rts
*******************************************************
** C Program exit() Function, return code on stack **
** **
** pr_ReturnAddr points to our RTS addr on stack **
** and we use this to calculate our stack ptr: **
** **
** SP -> WBenchMsg or 0 (CLI) **
** sVar ptr or 0 (QARG) **
** Address for RTS to DOS **
*******************************************************
_exit:
move.l 4(sp),d2 ; exit(n) return code to d2
exit2: ;exit code in d2
;------ restore initial stack ptr
;-- FindTask
movea.l ABSEXECBASE,a6
suba.l a1,a1
callsys FindTask
;-- get SP as it was prior to DOS's jsr to us
move.l d0,a4
move.l pr_ReturnAddr(a4),a5
;-- subtract 4 for return address, 4 for SVar, 4 for WBenchMsg
suba.l #12,a5
;-- restore sp
move.l a5,sp
;-- recover WBenchMsg
move.l (sp)+,a2
;-- recover SVar
move.l (sp)+,a5
IFGT WBOUT
;------ Close any WbOutput file before closing dos.library
move.l sv_WbOutput(a5),d1
beq.s noWbOut
move.l _DOSBase,a6
callsys Close
noWbOut:
;------ Restore a6 = ExecBase
movea.l ABSEXECBASE,a6
ENDC WBOUT
;------ Close DOS library, if we got here it was opened
; SysBase still in a6
movea.l _DOSBase,a1
callsys CloseLibrary
;------ if we ran from CLI, skip workbench reply
checkWB:
move.l a2,d0
beq.s deallocSV
bsr.s repWbMsg
deallocSV:
IFEQ QARG
;------ deallocate the SVar structure
move.l a5,a1
move.l sv_Size(a5),d0
callsys FreeMem
ENDC QARG
;------ this rts sends us back to DOS:
move.l d2,d0
rts
**********************************************************************
;----- PC relative data
DOSName DOSNAME
NilName dc.b 'NIL:',0
IFGT QARG
CNOP 0,2
nullArgV dc.l nullArg
nullArg dc.l 0 ; "" & the null entry after nullArgV
ENDC
**********************************************************************
DATA
**********************************************************************
_SysBase dc.l 0
_DOSBase dc.l 0
IFGT ASTART
_WBenchMsg dc.l 0
_stdin dc.l 0
_stdout dc.l 0
_stderr dc.l 0
_errno dc.l 0
ENDC ASTART
IFGT DEBUG
initialSP dc.l 0
dosCmdLen dc.l 0
dosCmdBuf dc.l 0
ENDC DEBUG
VerRev dc.w 36,13
IFGT ASTART
dc.b 'A'
ENDC ASTART
IFEQ ASTART
dc.b 'R'
ENDC ASTART
IFGT WINDOW
_NeedWStartup:
dc.b 'W'
ENDC WINDOW
IFEQ WBOUT
dc.b 'X'
ENDC WBOUT
IFGT NARGS
dc.b 'N'
ENDC NARGS
IFGT DEBUG
dc.b 'D'
ENDC DEBUG
IFGT QARG
dc.b 'Q'
ENDC QARG
END