home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Enigma Amiga Life 110
/
EnigmaAmiga110CD.iso
/
software
/
varie
/
run44
/
run.asm
< prev
Wrap
Assembly Source File
|
2000-01-27
|
25KB
|
1,197 lines
; FILE: Source:run.ASM REV: 12 --- run with detach
; History
; 0 started 5th Jan 2000. loosely based on kickstart 40.68
; internal run.
; 1 works. DETACH/S and QUIET/S not yet functional.
; 2 wrote forpath & findcommand for DETACH/S.
; 3 wrote detach routine for DETACH/S. Added STACK/K/N and
; PRI/K/N (work for non-detach mode too).
; 4 6th Jan 2000: DETACH/S: worked a bit on ReadItem() problem,
; now it finally works as expected. Made QUIET/S work.
; 5 DETACH/S: added proper ioerr to findcommand failure, added
; consistent error output, uses undocumented negative ioerr
; with PrintFault().
; 6 DETACH/S: won't load executable with E bit clear, now
; findcommand should find the command 100% the same as
; amigaos shell.
; 7 DETACH/S: removed Forbid() + FreeVec() hack from pr_ExitCode,
; uses AllocEntry() + TC_MEMLIST instead.
; 8 7th Jan 2000: now DETACH/S creates complete fake CLI
; structure.
; 9 now DETACH/S always adds exitcode to process because it also
; clears pr_Flags PRF_FREESEGLIST if pr_CLI.cli_Module gets
; cleared by command. this prevents crash if command has
; autodetach feature built in. nice.
; 10 DETACH/S exitcode: hmm, apparently clearing PRF_FREESEGLIST
; is not enough, now also clears item 3 from pr_SegList array.
; now seems to work properly. froze 44.1.beta1.
; 11 8th Jan 2000: DETACH/S used to copy PROGDIR: of `run' itself,
; caused missing PROGDIR: if `run' was made resident. Now sets
; it properly. As a side effect had to create better API for
; findcommand, now uses structure to pass things around.
; 12 27th Jan 2000: DETACH/S failed to create PROGDIR: correctly
; if programname had path components. Fixed & changed
; findcommand API a bit. froze 44.1 aminet release.
;
; installation:
;
; protect source:run prwed
; resident run remove
; resident source:run add
; defaults
MIN_STACK EQU 512 ; minimum stack allowed
MAX_PRI EQU 127 ; maximum priority allowed
MIN_PRI EQU -128 ; minimum priority allowed
DIR_LEN EQU 80 ; maximum cli_SetName len
COMMNAME_LEN EQU 104 ; maximum cli_CommandName len
PROMPT_LEN EQU 60 ; maximum cli_Prompt len
SUBQ1ABS_OPCODE EQU $53B9 ; subq.l #1,(abs).l
; flags for conditional compiling
USE_TC_MEMLIST EQU 1
include "exec/lists.i"
include "exec/libraries.i"
include "exec/memory.i"
include "dos/dos.i"
include "dos/dosextens.i"
include "dos/rdargs.i"
include "dos/dostags.i"
include "exec/exec_lib.i"
include "dos/dos_lib.i"
call MACRO
jsr (_LVO\1,a6)
ENDM
STRUCTURE stackdata,0
APTR sd_execbase
APTR sd_dosbase
APTR sd_rdargs
LABEL sd_args
LONG sd_detach
LONG sd_quiet
LONG sd_stack
LONG sd_pri
APTR sd_command
ALIGNLONG
LABEL sd_SIZEOF
; ---> detach routine
BITDEF DETACH,USENIL,0
; <--- detach routine
; ---> findcommand routine
STRUCTURE fcmd,0
BPTR fcmd_seglist ; in: 0 out: seglist
LABEL fcmd_nameptr ; in: char *
BPTR fcmd_homedir ; out: BPTR
LONG fcmd_subqpos ; in: 0 out: &seg_UC if res, else 0
APTR fcmd_internal ; internal stuff
LABEL fcmd_SIZEOF
; <--- findcommand routine
Main movem.l d2-d3/d6-d7/a3-a6,-(sp)
moveq #sd_SIZEOF/4,d0
.clr clr.l -(sp)
subq.l #1,d0
bne.b .clr
move.l sp,a5
move.l (4).w,a6
moveq #RETURN_ERROR,d7
move.l a6,(a5)
lea (dosname,pc),a1
moveq #39,d0
call OpenLibrary
move.l d0,(sd_dosbase,a5)
beq .cleanup
move.l (sd_dosbase,a5),a6
lea (template,pc),a0
move.l a0,d1
lea (sd_args,a5),a0
move.l a0,d2
moveq #0,d3
call ReadArgs
move.l d0,(sd_rdargs,a5)
bne.b .argsok
call IoErr
move.l d0,d1
moveq #0,d2
call PrintFault
bra .cleanup
.argsok
; check priority validity:
move.l (sd_pri,a5),d0
beq.b .priok
move.l d0,a0
move.l (a0),d0
cmp.l #MAX_PRI,d0
ble.b .nottoohigh
moveq #MAX_PRI,d0
.nottoohigh cmp.l #MIN_PRI,d0
bge.b .nottoolow
moveq #MIN_PRI,d0
.nottoolow move.l d0,(a0)
.priok
; check stack validity:
move.l (sd_stack,a5),d0
beq.b .stackok
move.l d0,a0
move.l (a0),d0
cmp.l #MIN_STACK,d0
bge.b .stackok
move.l #MIN_STACK,(a0)
.stackok
; `old way' run or detach?
tst.l (sd_detach,a5)
bne .detach
; this code fragment builds fake filehandle
; that feeds System() with COMMAND/F argument.
; this is the way amigaos does it. hacky ain't it?
;
; System() will free memory allocated...
; could maybe use AllocDosObject DOS_FILEHANDLE ?
;
move.l (sd_command,a5),a4
move.l a4,d0
bne.b .cmdok
lea (nullstr,pc),a4
.cmdok
moveq #-1,d6
move.l a4,a0
.len addq.l #1,d6
tst.b (a0)+
bne.b .len
moveq #fh_SIZEOF+14+2,d0
add.l d6,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
move.l (a5),a6
call AllocVec
tst.l d0
beq .cleanup
move.l d0,a3
lea (fh_SIZEOF,a3),a0
move.l a0,d0
asr.l #2,d0
move.l d0,(fh_Buf,a3)
move.l d6,d0
beq.b .nocopy
.bcopy move.b (a4)+,(a0)+
subq.l #1,d0
bne.b .bcopy
.nocopy
move.b #10,(a0)+
move.b #10,(a0)
addq.l #2,d6
move.l a3,d2
move.l d6,(fh_End,a3)
move.l (sd_dosbase,a5),a6
asr.l #2,d2
move.l sp,a2
clr.l -(sp)
pea (1).w
pea SYS_UserShell
call Output
move.l d0,-(sp)
pea SYS_Output
move.l d2,-(sp)
pea SYS_Input
move.l (sd_stack,a5),d0
beq.b .nostack
move.l d0,a0
move.l (a0),-(sp)
pea NP_StackSize
.nostack
move.l (sd_pri,a5),d0
beq.b .nopri
move.l d0,a0
move.l (a0),-(sp)
pea NP_Priority
.nopri
moveq #0,d1
move.l sp,d2
call SystemTagList
move.l a2,sp
move.l d0,d7
addq.l #1,d0
bne.b .cleanup
moveq #RETURN_ERROR,d7
.cleanup move.l (sd_dosbase,a5),d0
beq.b .nodos
move.l d0,a6
move.l (sd_rdargs,a5),d1
beq.b .no_freeargs
call FreeArgs
.no_freeargs move.l (sd_dosbase,a5),a1
move.l (a5),a6
call CloseLibrary
.nodos lea (sd_SIZEOF,sp),sp
move.l d7,d0
movem.l (sp)+,d2-d3/d6-d7/a3-a6
rts
.detach move.l #$80000000,d1
move.l (sd_pri,a5),d0
beq.b .use_defpri
move.l d0,a0
move.l (a0),d1
.use_defpri
move.l (sd_stack,a5),d2
beq.b .use_defstack
move.l d2,a0
move.l (a0),d2
.use_defstack
moveq #0,d0
tst.l (sd_quiet,a5)
beq.b .noquiet
moveq #DETACHF_USENIL,d0
.noquiet
move.l (sd_command,a5),a0
bsr.b detach ; has internal check for null a0
tst.l d0
beq.b .cleanup
moveq #RETURN_OK,d7
bra.b .cleanup
; detach - run given command as background process with fake cli
; structure.
;
; IN: a0=char *commandline (will be modified)
; a6=dosbase
; d0=flags
; d1=priority, $80000000 = use default
; d2=stacksize, 0 = use default
; OUT: d0=success
;
detach movem.l d0-d7/a0-a6,-(sp)
move.l d0,d6
move.l sp,a5
clr.l (sp)
move.l (4).w,d7
move.l a0,d0 ; null commandline?
beq .exit ; eek, quit!
tst.b (a0)
beq .exit ; eek, quit!
moveq #0,d4
moveq #0,d5
IFNE USE_TC_MEMLIST
move.w #-1,a4
ELSE
sub.l a4,a4
ENDC
; get commandline len
move.l (8*4,sp),a0 ; get a0 from stack
moveq #-1,d0
.len addq.l #1,d0
tst.b (a0)+
bne.b .len
; build CSource structure to stack
lea (-COMMNAME_LEN,sp),sp ; storage for commandname
clr.b (sp) ; nullterminate! (for .argfail)
move.l sp,d1 ; buffer
clr.l -(sp) ; CS_CurChr
move.l d0,-(sp) ; CS_Length
move.l (8*4,a5),-(sp) ; CS_Buffer (get a0 from stack)
moveq #COMMNAME_LEN-1,d2 ; maxchars
move.l sp,d3 ; struct CSource *
call ReadItem
moveq #0,d3 ; d3=homedir lock ptr!
move.l (sp)+,a0 ; CS_Buffer
move.l (sp)+,d1 ; CS_Length
add.l (sp)+,a0 ; add CS_CurChr
tst.l d0
bmi .argfail
; skip some chars if needed, needed because ReadItem()
; does UnGetC... stupid.
subq.l #2,d1 ; must have at least one char
bmi.b .singlearg
cmp.b #' ',(-1,a0)
beq.b .noskip
addq.l #1,a0
bra.b .noskip
.singlearg tst.b (a0)+ ; make a0 point nullchar
bne.b .singlearg
subq.l #1,a0
.noskip
; a0 = after first param = command arguments.
; quite neat eh? OS rules ;)
; lf + null terminate a0 string,
; this is really needed, NP_Arguments &
; ReadArgs() require this
move.l (8*4,a5),a1 ; get a0 from stack
.copy move.b (a0)+,(a1)+
bne.b .copy
move.b #10,(-1,a1)
move.b #0,(a1)
; if USENIL flag is set don't open console:
; filehandles, but use default nil: i/o
btst #DETACHB_USENIL,d6
bne.b .use_nil1
lea (.conname,pc),a2
move.l a2,d1
move.l #MODE_NEWFILE,d2
call Open
move.l d0,d5
beq .filefail
move.l a2,d1
;move.l #MODE_NEWFILE,d2
call Open
move.l d0,d4
beq .filefail
.use_nil1
; build taglist for CreateNewProc to stack
clr.l -(sp)
move.l (8*4,a5),-(sp) ; get a0 from stack
pea NP_Arguments
pea (-COMMNAME_LEN,a5) ; commandname
pea NP_Name
; find command seglist, uses findcommand subroutine
; build findcommand structure to stack
subq.l #4,sp ; fcmd_internal
clr.l -(sp) ; fcmd_subqpos
pea (-COMMNAME_LEN,a5) ; in: fcmd_nameptr / out: fcmd_homedir
clr.l -(sp) ; fcmd_seglist
move.l sp,a0
bsr findcommand
move.l (sp)+,a3 ; get fcmd_seglist
move.l (sp)+,d1 ; get fcmd_homedir
move.l (sp)+,a2 ; get fcmd_subqpos
addq.l #4,sp ; pop fcmd_internal
tst.l d0
beq .nocommand
move.l d1,d3 ; d1=fcmd_homedir
; make PROGDIR: work...
move.l d3,-(sp)
pea NP_HomeDir
; if the command found was (not internal) resident we
; must prepare ourselves to decrement its seg_UC
; after executing it. this requires some hacking
; namely use of NP_ExitCode to pass code to be run
; after program termination and some way to free the
; memory fragment allocated for that code.
;
; there are two ways to handle the memory freeing,
; either Forbid() & free the memory in exitcode
; itself or use task TCB's TC_MEMLIST to free it.
; latter is more OS legal, but requires sorrounding
; CreateNewProc() with Forbid()/Permit() pair.
;
; but then, we need to forbid there anyways, because
; of pr_CLI faking so USE_TC_MEMLIST method is better.
;
; this exitcode also handles cli_Module=NULL seglist
; cutting, this prevents potential problems if
; command has some autodetach logic built in.
exg d7,a6
IFNE USE_TC_MEMLIST
; build MemEntry to stack
pea (exitcode_SIZEOF).w
pea (MEMF_PUBLIC).w Entry #0
pea (1).w Number of entries (longword zeropadded)
lea (-(LN_SIZE-2),sp),sp Reserve space for list node (-2 = padding...)
move.l sp,a0
call AllocEntry
lea ((LN_SIZE-2)+(3*4),sp),sp
exg d7,a6
tst.l d0
bmi .nomem
move.l d0,a4
move.l (ML_ME+0*ME_SIZE,a4),a1
ELSE
moveq #exitcode_SIZEOF,d0
moveq #MEMF_PUBLIC,d1
call AllocVec
exg d7,a6
tst.l d0
beq .nomem
move.l d0,a4
move.l d0,a1
ENDC
; copy the exitcode to newly allocated memory:
exg d7,a6
lea (.exitcode,pc),a0
moveq #exitcode_SIZEOF,d0
call CopyMem
; if we need to decrement seg_UC add subq instruction:
move.l a2,d0
beq.b .no_subqinst
IFNE USE_TC_MEMLIST
move.l (ML_ME+0*ME_SIZE,a4),a0
;lea (.subqaddr-.exitcode,a0),a0
ELSE
;lea (.subqaddr-.exitcode,a4),a0
move.l a4,a0
ENDC
move.w #SUBQ1ABS_OPCODE,(a0)+
move.l a2,(a0)
.no_subqinst
; we just built code to be executed so better clear
; CPU caches...
call CacheClearU
exg d7,a6
; stuff exitcode
IFNE USE_TC_MEMLIST
move.l (ML_ME+0*ME_SIZE,a4),-(sp)
ELSE
move.l a4,-(sp)
ENDC
pea NP_ExitCode
; ask OS to free the seglist when done (default)
pea (1).w
pea NP_FreeSeglist
; pass the seglist pointer
move.l a3,-(sp)
bpl.b .segptok
; seglist pointer was negative so we must negate it to
; get real pointer. this also indicates that this seglist
; should not be unloadseg'd when done so clear ti_Data of
; NP_FreeSeglist tag.
neg.l (sp)
clr.l (8,sp) ; clear ti_Data of NP_FreeSeglist
.segptok pea NP_Seglist
; if we were given a priority, stuff tag indicating it
move.l (1*4,a5),d0 ; get d1 from stack
cmp.l #$80000000,d0
beq.b .use_defpri
move.l d0,-(sp)
pea NP_Priority
.use_defpri
; put NP_StackSize tag.
; if d2 was <>0 then use that value as stack size
move.l (2*4,a5),-(sp) ; get d2 from stack
bne.b .notcli
; so d2 was zero then, lets try to peek out default
; value to use. strategy:
; 1) if CLI process get cli_DefaultStack
; 2) not CLI process: use pr_StackSize or 4000,
; whichever is larger
exg d7,a6
sub.l a1,a1
call FindTask
exg d7,a6
move.l d0,a0
move.l (pr_StackSize,a0),d0
cmp.l #4000,d0
bhs.b .prstackok
move.l #4000,d0
.prstackok move.l d0,(sp)
call Cli
tst.l d0
beq.b .notcli
move.l d0,a0
move.l (cli_DefaultStack,a0),d0
lsl.l #2,d0 ; must *4
move.l d0,(sp)
.notcli pea NP_StackSize
; put NP_Output and NP_Input tags, unless USENIL flag
btst #DETACHB_USENIL,d6
bne.b .use_nil2
move.l d5,-(sp)
pea NP_Output
move.l d4,-(sp)
pea NP_Input
.use_nil2
; allocate the fake CLI structure
clr.l -(sp)
pea (DIR_LEN).w
pea ADO_DirLen ; size in bytes for current dir buffer
pea (COMMNAME_LEN).w
pea ADO_CommNameLen ; size in bytes for command name buffer
pea (PROMPT_LEN).w
pea ADO_PromptLen ; size in bytes for the prompt buffer
move.l sp,d2
moveq #DOS_CLI,d1
call AllocDosObject
lea (7*4,sp),sp ; pop stack
move.l d0,d2
beq .nocli
; also, for completeness, we need to poke in some
; standard values to CLI structure. this ensures
; that program using them will not choke.
movem.l d2-d3/a2,-(sp) ; must store d2-d3/a2 for .procfail!
move.l d2,a2
lea (-DIR_LEN,sp),sp ; temp string storage
; set cli_SetName:
move.l sp,d1
moveq #DIR_LEN-1,d3
call GetCurrentDirName
move.l sp,a0
move.l (cli_SetName,a2),a1
bsr .cstr2bstr
; set cli_CommandName:
lea (-COMMNAME_LEN,a5),a0
move.l (cli_CommandName,a2),a1
bsr .cstr2bstr
; copy parent's prompt:
move.l sp,d1
moveq #PROMPT_LEN-1,d2
call GetPrompt
move.l sp,a0
move.l (cli_Prompt,a2),a1
bsr .cstr2bstr
;cli_CommandFile will be nullstr.
; default defaultstack :)
move.l #4096/4,(cli_DefaultStack,a2)
; copy parent's cli_DefaultStack & cli_FailLevel:
call Cli
tst.l d0
beq.b .noparent
move.l d0,a0
move.l (cli_DefaultStack,a0),(cli_DefaultStack,a2)
move.l (cli_FailLevel,a0),(cli_FailLevel,a2)
; copy parent's cli_CommandDir
move.l (cli_CommandDir,a0),d0
bsr copycommanddir
move.l d0,(cli_CommandDir,a2)
.noparent
; set cli_Module:
move.l a3,(cli_Module,a2)
bpl.b .segptok2
neg.l (cli_Module,a2)
.segptok2
lea (DIR_LEN,sp),sp ; pop temp string storage
movem.l (sp)+,d2-d3/a2
; must forbid because we change newly created
; process before it will be run.
exg d7,a6
call Forbid
exg d7,a6
; create the process!
move.l sp,d1
call CreateNewProc
; if failed, get out and free everything we
; allocated.
tst.l d0
beq.b .procfail
; if we're using USE_TC_MEMLIST exitcode strategy
; we must now link it to task's TC_MEMENTRY in order
; it to get FreeEntry()'d on RemTask().
move.l d0,a2 ; can trash a2 here
IFNE USE_TC_MEMLIST
lea (TC_MEMENTRY,a2),a0
move.l a4,a1
ADDHEAD
ENDC
; now we only need to poke in the fake CLI structure
; for the process (set BPTR(cli) to pr_CLI) and ask
; process to free it when it will exit (set
; PRF_FREECLI in pr_Flags).
move.l d2,a0
; set cli_StandardInput & cli_CurrentInput:
move.l (pr_CIS,a2),(cli_StandardInput,a0)
move.l (pr_CIS,a2),(cli_CurrentInput,a0)
; set cli_CurrentOutput & cli_StandardOutput:
move.l (pr_COS,a2),(cli_StandardOutput,a0)
move.l (pr_COS,a2),(cli_CurrentOutput,a0)
lsr.l #2,d2 ; APTR->BPTR
move.l d2,(pr_CLI,a2) ; set pr_CLI
or.w #PRF_FREECLI,(pr_Flags+2,a2) ; set PRF_FREECLI
exg d7,a6
call Permit ; let it run!
addq.l #1,(a5) ; return success
.exit move.l a5,sp
movem.l (sp)+,d0-d7/a0-a6
rts
.procfail exg d7,a6
call Permit
exg d7,a6
moveq #4,d1 ;DOS_CLI
;move.l d2,d2
call FreeDosObject
.nocli
IFNE USE_TC_MEMLIST
move.l a4,d0
bmi.b .nomem
exg d7,a6
move.l a4,a0
call FreeEntry
ELSE
move.l a4,d0
beq.b .nomem
exg d7,a6
move.l a4,a1
call FreeVec
ENDC
exg d7,a6
.nomem
move.l a2,d0
beq.b .nosub
subq.l #1,(a2) ; decrement seg_UC
.nosub move.l a3,d1 ; unload the segment
bmi.b .nounload ; *only* when needed
call UnLoadSeg
.nounload
.nocommand
.filefail
.argfail call IoErr
move.l d0,d2
move.l d3,d1
beq.b .nol
call UnLock
.nol move.l d4,d1
beq.b .noc1
call Close
.noc1 move.l d5,d1
beq.b .noc2
call Close
.noc2
cmp.l #ERROR_OBJECT_NOT_FOUND,d2
bne.b .othererr
; uses undocumented feature of PrintFault() here.
; if you give it negative value it outputs some
; predefined string from internal table.
; locale.library will patch this table with current
; language's strings. this way we stay 100% language
; independent and don't need separate locale support.
moveq #-121,d1 ; "Unknown command" (in english)
lea (-COMMNAME_LEN,a5),a0
move.l a0,d2
bra.b .pfault
.othererr
move.l d2,d1
moveq #0,d2
.pfault call PrintFault
bra.b .exit
; copy str to bstr & fix bstr len
.cstr2bstr move.l a2,d0
add.l a1,a1
add.l a1,a1
move.l a1,a2
st (a1)+ ; put -1 to count
.cs2bsl addq.b #1,(a2) ; increment count
move.b (a0)+,(a1)+ ; copy chars, until zero
bne.b .cs2bsl
move.l d0,a2
rts
; IN: d0=rc
; d1=exitdata
; a6=execbase (documented?)
; OUT: d0=rc
.exitcode
.subqaddr dc.w $6004,$dead,$c0de
movem.l d0/a6,-(sp)
move.l (4).w,a6
sub.l a1,a1
call FindTask
move.l d0,a1
; pr_CLI can be null if someone has
; released it. we must prepare.
move.l (pr_CLI,a1),d0
beq.b .ec_nocli
lsl.l #2,d0
move.l d0,a0
tst.l (cli_Module,a0)
bne.b .ec_gotmodule
and.w #~PRF_FREESEGLIST,(pr_Flags+2,a1)
move.l (pr_SegList,a1),d0 ; get BPTR to array of seglist used...
lsl.l #2,d0 ; BPTR->APTR
move.l d0,a0
clr.l (12,a0) ; really prevent unloading!
.ec_gotmodule
.ec_nocli
IFEQ USE_TC_MEMLIST
call Forbid ; we'll free ourself...
lea (.exitcode,pc),a1 ; set us free !-)
call FreeVec ; return + run rest of the code
; in Forbid() state. RemTask(0)
; will end this soon... :)
ENDC
movem.l (sp)+,d0/a6
rts
exitcode_SIZEOF EQU *-.exitcode
.conname dc.b 'console:',0
CNOP 0,2
; copycommanddir - create copy of cli_CommandDir
;
; IN: d0=BPTR commanddir
; a6=dosbase
; OUT: d0=BPTR newcommanddir
;
copycommanddir movem.l d7/a3-a6,-(sp)
clr.l -(sp)
move.l (4).w,d7
move.l d0,a5
move.l sp,a4
bra.b .gocopy
.copy exg d7,a6
moveq #8,d0
moveq #MEMF_PUBLIC,d1
call AllocVec
tst.l d0
beq.b .exit
exg d7,a6
move.l d0,a3
move.l (4,a5),d1 ; from->lock
call DupLock
move.l a3,d1
lsr.l #2,d1
move.l d1,(a4) ; pred->succ=BPTR(this)
move.l a3,a4 ; pred=this
clr.l (a3)+ ; this->succ=NULL
move.l d0,(a3) ; this->lock=lock
move.l (a5),a5 ; from=from->succ
.gocopy add.l a5,a5 ; from=APTR(from)
add.l a5,a5
move.l a5,d0
bne.b .copy
.exit movem.l (sp)+,d0/d7/a3-a6
rts
STRUCTURE data,0
APTR d_seglistptr
LABEL d_nameptr
APTR d_homedir
APTR d_subqpos
APTR d_fib
LABEL data_SIZEOF
; findcommand - find command and return its seglist, scans resident
; list first, then shell path(s).
;
; IN: a0=struct fcmd *findcommand,
; fcmd_seglist = 0
; fcmd_nameptr = char *commandname, command name to find
; fcmd_subqpos = 0
; a6=dosbase
; OUT: d0=success, if succeeded structure passed in is filled:
; a0=struct fcmd *findcommand,
; fcmd_seglist = BPTR seglist, if positive call UnLoadSeg
; for it when done.
; fcmd_homedir = BPTR lock, MUST be UnLock()ed when done!
; NULL for resident cmds.
; fcmd_subqpos = ULONG *subpos, if <>0 must decrement 1 from
; longword pointed when command has finished
; (this is resident command usecount).
;
; NOTE: if findcommand fails, all fields are zeroed and ioerr
; will be set to ERROR_OBJECT_NOT_FOUND.
;
findcommand movem.l d2-d7/a0/a2-a6,-(sp)
move.l a0,a5
move.l (4).w,d7
; we need FileInfoBlock for examine...
moveq #DOS_FIB,d1
moveq #0,d2
call AllocDosObject
move.l d0,(d_fib,a5)
beq .nofib
; first check if command has any path elements
; in its name. if it has then split directory and
; file names, and try to load the command.
; If succeeds, progdir is the PathPart() of the
; path.
move.l (d_nameptr,a5),d2
move.l d2,d1
call PathPart
cmp.l d0,d2
beq.b .nofix
; ok. it does have path elements.
move.l d0,a2
move.l d0,d1
call FilePart
move.l (d_nameptr,a5),d4
move.l d0,(d_nameptr,a5)
move.b (a2),d6
clr.b (a2) ; cut filename
move.l d4,d1
moveq #ACCESS_READ,d2 ; note: d2<>0 !
call Lock
move.b d6,(a2) ; fix filename
move.l d0,d3
beq.b .nopath
; d0=lock, a1=data, a6=dosbase
move.l a5,a1
bsr .findroutine
move.l d0,d2
; cleanup...
move.l d3,d1
call UnLock
; don't try to fix d_nameptr here!
tst.l d2
beq .exit ; found it! quit
.nopath
move.l d4,(d_nameptr,a5)
.nofix
; try to find command from resident list
exg d7,a6
call Forbid
exg d7,a6
; first try system segments...
moveq #1,d3 ; system segments
bsr.b .findseg
tst.l (a5) ; found seglist?
bne.b .foundit ; yeah, exit
; we didn't find it from system segment list, try
; normal segment list then...
moveq #0,d3 ; normal segments
bsr.b .findseg
.foundit
exg d7,a6
call Permit
exg d7,a6
tst.l (a5) ; found seglist?
bne.b .exit ; yeah, exit
; ok, so we could not find command from resident list,
; lets try to find it somewhere within shell path(s)...
; (uses forpath subroutine here)
lea (.findroutine,pc),a0 ; routine
move.l a5,a1 ; data
bsr forpath ; do it!
tst.l (a5) ; got seglist?
bne.b .exit ; yep, quit
; could not find command, set ioerr accordingly
move.l #ERROR_OBJECT_NOT_FOUND,d1
call SetIoErr
.exit
move.l (d_fib,a5),d2 ; get fib
beq.b .nofib
moveq #DOS_FIB,d1
call FreeDosObject
.nofib
move.l (a5),d0 ; return success flag
bne.b .exitok
; call failed, make sure fcmd structure is zeroed:
clr.l (fcmd_homedir,a5)
clr.l (fcmd_subqpos,a5)
.exitok
movem.l (sp)+,d2-d7/a0/a2-a6
rts
.findseg move.l (fcmd_nameptr,a5),d1
moveq #0,d2
call FindSegment
tst.l d0
beq.b .fs_no
move.l d0,a0
addq.l #seg_UC,a0
cmp.l #CMD_DISABLED,(a0) ; disabled internal command?
beq.b .fs_no ; yeah, don't use this!
move.l (seg_Seg-seg_UC,a0),(a5) ; get seglist
neg.l (a5) ; mark non-UnLoadSeg()
; resident cmd has no home dir!
clr.l (fcmd_homedir,a5)
tst.l (a0) ; seg_UC negative?
bmi.b .fs_no ; yeah, don't increment
addq.l #1,(a0) ; increment usecount!
move.l a0,(fcmd_subqpos,a5) ; set seg_UC ptr
.fs_no rts
; this routine checks one path element for
; command.
.findroutine movem.l d2-d4/a2,-(sp)
; d0=lock, a1=data, a6=dosbase
move.l a1,a2
; change currentdir
move.l d0,d1
call CurrentDir
move.l d0,d3
; try to get a lock
move.l (d_nameptr,a2),d1
moveq #ACCESS_READ,d2
call Lock
move.l d0,d4
beq.b .fr_nolock
; examine the lock
move.l d4,d1
move.l (d_fib,a2),d2
call Examine
tst.l d0
beq.b .fr_bad
; must have e bit clear (read: set)
move.l (d_fib,a2),a0
btst #FIBB_EXECUTE,(fib_Protection+3,a0)
bne.b .fr_bad
; try to load as executable
move.l (d_nameptr,a2),d1
call LoadSeg
move.l d0,(a2) ; d_seglistptr
.fr_bad
move.l d4,d1
call UnLock
.fr_nolock
; change back to old dir
move.l d3,d1
call CurrentDir
move.l d0,d1 ; d1=path lock
; found it? (d_seglistptr)
moveq #1,d0 ; default: continue
tst.l (a2)
beq.b .fr_exit ; nope!
; d1=lock
call DupLock
move.l d0,(d_homedir,a2) ; return homedir!
moveq #0,d0 ; terminate
.fr_exit
movem.l (sp)+,d2-d4/a2
rts
; forpath - call subroutine for each path element of process,
; if there is no CLI structure for process uses standard paths
; currentdir and c:.
;
; IN: a0=function to call
; a1=args to function
; a6=dosbase
; OUT: d0=number of path elements encounted
; function is called with:
; IN: a0=pointer to self
; a1=args to function
; a6=dosbase
; d0=lock of this path
; OUT: d0=zero will break out from loop
;
forpath movem.l d1-d7/a0-a6,-(sp)
moveq #0,d7
moveq #0,d1
call CurrentDir
move.l d0,d2
move.l d0,d1
call CurrentDir
move.l d2,d0
movem.l (7*4,sp),a0-a1
movem.l d7/a6,-(sp)
jsr (a0)
movem.l (sp)+,d7/a6
tst.l d0
beq.b .exit
addq.l #1,d7
call Cli
tst.l d0
beq.b .nocli
move.l d0,a2
move.l (cli_CommandDir,a2),d0
beq.b .nocli
lsl.l #2,d0
move.l d0,a2
movem.l (7*4,sp),a0-a1
.more move.l (4,a2),d0 ;lock
movem.l d7/a0-a2/a6,-(sp)
jsr (a0)
movem.l (sp)+,d7/a0-a2/a6
tst.l d0
beq.b .exit
addq.l #1,d7
move.l (a2),d0 ;next
lsl.l #2,d0
move.l d0,a2
bne.b .more
.nocli lea (.stdpath,pc),a0
move.l a0,d1
moveq #ACCESS_READ,d2
call Lock
move.l d0,d6
beq.b .exit
movem.l (7*4,sp),a0-a1
movem.l d6-d7/a6,-(sp)
jsr (a0)
movem.l (sp)+,d6-d7/a6
tst.l d0
beq.b .nc_exit
addq.l #1,d7
.nc_exit move.l d6,d1
call UnLock
.exit move.l d7,d0
movem.l (sp)+,d1-d7/a0-a6
rts
.stdpath dc.b 'c:',0
CNOP 0,2
dc.b '$VER: run 44.1 (27.1.00)',0
dosname dc.b 'dos.library',0
nullstr EQU *-1
template dc.b 'DETACH/S,QUIET/S,STACK/K/N,PRI/K/N,COMMAND/F',0