Path: utzoo!mnetor!uunet!mcvax!unido!rmi!kkaempf From: kkaempf@rmi.UUCP (Klaus Kaempf) Newsgroups: comp.sys.amiga Subject: Execute() Message-ID: <857@rmi.UUCP> Date: 22 Jan 88 15:40:47 GMT Reply-To: kkaempf@rmi.UUCP Organization: RMI Net, Aachen, W.Germany Lines: 385 Keywords: shell, BCPL, AmigaDOS, fork(), fexec() Wanna call a CLI-command in your own application? Maybe you don't have "RUN" in your "C:" directory? Or it's "PROMPT", "STACK", "CD" or the like? So forget "Execute()"! But it's one of these BCPL programs - darn! Try this one! This small program can be used to execute CLI-commands, even the ones that rely on the correct BCPL setup. Two restrictions: "System0()" must be called from a CLI-PROCESS (or SHELL or whatever). You cannot call it from WorkBench, a simple task or interrupt (argh!). "EXECUTE" (the CLI-command) will not loop through the batchfile itself, but rather change the "cli_CurrentInput", so the shell will execute the incoming lines until "EOF" is encountered and then restore "cli_CurrentInput". So this is not a restriction, if you return to the input-loop directly after "System0()" has been called (normally true in shell program). Batchfiles called this way may be nested, but do not try to "EXECUTE" several batch-files ... System0("Execute", seglist, "first"); System0("Execute", seglist, "second"); System0("Execute", seglist, "third"); ... without returning to the input-loop first. "System0()" WON'T handle loading and unloading of the code, I/O-redirection or whatever, but this is fairly simple. Commands should be checked in the following order: built-in commands of the shell resident commands ("NetHand") current directory (WindowPtr = -1) path list ("CommandDir", WindowPtr = -1) "C:" (WindowPtr = 0) As an option for shells: Try to execute it as a batchfile (current directory or "S:"), if everything else fails (but use "WindowPtr = -1" for "C:" then). I/O-redirection should save the values of "pr_CIS" and "pr_COS", put the new ones into these fields and restore them after the command has finished. That's why "EXECUTE" is not that much impressed if you supply it with ">" or "<". "System0()" returns the return code (register D0 or "Exit()"-parameter) of the program called (not the same as "Execute()"!), or an internal error code: -1: process not a CLI -2: not enough memory for stack It does not rely on some strange undocumented data structures the way Aztec's "fexec#?()" does. You do not need a special startup code to save the registers (Csh 2.04). I still have to find the command, that cannot be called this way, but you will certainly manage this. :-) Two non-standard include files are used. "extern/exec.i" contains the "_LVO" equates for "exec", you can use "amiga.lib" instead. "extras/asm.i" provides ... AbsExecBase equ 4 REG_SysBase equr a6 callsys macro jsr _LVO\1(REG_SysBase) endm The uuencoded object file has been created using the Metacomco Macro Assembler. A new release (11.1) of this one has been announced for the ST, does anybody have further information about an Amiga-version? multam salutem omnibus !ralph P.S.: If someone would be as kind as to mail me a disk with the latest version of Matt's shell for Lattice-C? Thanks! ################ * * System0.asm - invoke system's command processor * * Copyright (C) by Ralph Babel, Guru Meditation Network, * Falkenweg 3, D-6204 Taunusstein, West-Germany * * This piece of code may be used as part of any product as * long as the source code for the complete program can be * obtained free of charge (except for a small copying fee) * and this copyright notice is left unchanged. * * Bug reports and improved versions appreciated. * * 20-Jul-1987 created original version * 11-Jan-1988 now based on "official" information only * nolist include "exec/types.i" include "libraries/dos.i" include "libraries/dosextens.i" include "extern/exec.i" include "extras/asm.i" list * * LONG System0(name, seglist, args) * char *name; * BPTR seglist; * char *args; * xdef _System0 xref _DOSBase * parameter offsets & stack SAVED_REGS reg a2-a6/d2-d3 DELTA equ 7*4 ARG_NAME equ 4+DELTA ARG_SEGLIST equ 8+DELTA ARG_ARGS equ 12+DELTA * additional return codes NO_CLI equ -1 NO_MEM equ -2 * local constants MAXBSTR equ 255 LF equ 10 * register usage REG_Result equr d3 REG_Process equr a2 ;may not be A4, see below! REG_CLI equr a3 REG_CIS equr a4 ;may not be A3, see below! REG_PrevStack equr a5 * local stack frame STRUCTURE StackFrame,0 STRUCT sf_CommandName,MAXBSTR+1 ;BSTR, length byte! STRUCT sf_CommandArgs,MAXBSTR+1 ;not a BSTR, LF-terminated! APTR sf_PrevStack APTR sf_SaveReturnAddr BPTR sf_SaveModule BPTR sf_SaveCommandName APTR sf_StackBase LONG sf_StackSize LONG sf_PushSize APTR sf_Process APTR sf_CLI APTR sf_CIS BPTR sf_SCB_Buf LONG sf_SCB_Pos LONG sf_SCB_End LABEL sf_SIZEOF * entry point _System0: movem.l SAVED_REGS,-(sp) moveq #NO_CLI,REG_Result ;ERROR - not a CLI task movea.l AbsExecBase,REG_SysBase suba.l a1,a1 callsys FindTask ;find own task movea.l d0,REG_Process move.l pr_CLI(REG_Process),d0 beq quit0 * build local stack frame & save some values lsl.l #2,d0 ;BPTR to machine pointer movea.l d0,REG_CLI movea.l sp,REG_PrevStack ;save old stack pointer move.l sp,d0 andi.b #$fc,d0 ;make SP longword-aligned for BPTRs movea.l d0,sp suba.w #sf_SIZEOF,sp move.l REG_PrevStack,sf_PrevStack(sp) move.l REG_Process,sf_Process(sp) move.l REG_CLI,sf_CLI(sp) move.l pr_ReturnAddr(REG_Process),sf_SaveReturnAddr(sp) * allocate space for stack moveq #NO_MEM,REG_Result ;ERROR - no memory for STACK move.l cli_DefaultStack(REG_CLI),d0 ;in longwords for "VEC" lsl.l #2,d0 move.l d0,sf_PushSize(sp) addq.l #4,d0 ;one additional longword move.l d0,sf_StackSize(sp) moveq #0,d1 ;intentionally NOT "MEMF_PUBLIC"! callsys AllocMem tst.l d0 beq quit1 move.l d0,sf_StackBase(sp) ;save result * save old command pointer, build new BCPL command name move.l cli_CommandName(REG_CLI),sf_SaveCommandName(sp) movea.l ARG_NAME(REG_PrevStack),a0 ;first parameter to "System0()" lea sf_CommandName+1(sp),a1 ;first char location for BSTR move.l a1,d0 lsr.l #2,d0 ;will ignore (+1), BPTR as result move.l d0,cli_CommandName(REG_CLI) move.w #MAXBSTR,d0 bra.s 2$ 1$ move.b d1,(a1)+ 2$ move.b (a0)+,d1 dbeq d0,1$ suba.l ARG_NAME(REG_PrevStack),a0 ;subtract original source move.l a0,d0 subq.l #1,d0 ;terminating null-byte move.b d0,sf_CommandName(sp) ;to first location in BSTR * save contents of Current Input Stream move.l pr_CIS(REG_Process),d0 lsl.l #2,d0 movea.l d0,REG_CIS ;contains APTR to CIS move.l REG_CIS,sf_CIS(sp) move.l fh_Buf(REG_CIS),sf_SCB_Buf(sp) move.l fh_Pos(REG_CIS),sf_SCB_Pos(sp) move.l fh_End(REG_CIS),sf_SCB_End(sp) * convert argument to LF-terminated string movea.l ARG_ARGS(REG_PrevStack),a0 ;third argument to "System0()" lea sf_CommandArgs(sp),a1 ;first buffer location move.l a1,d0 lsr.l #2,d0 ;make buffer pointer a BPTR move.l d0,fh_Buf(REG_CIS) move.w #MAXBSTR,d0 ;leave some room for terminating LF bra.s 4$ 3$ move.b d1,(a1)+ 4$ move.b (a0)+,d1 dbeq d0,3$ move.b #LF,(a1) suba.l ARG_ARGS(REG_PrevStack),a0 ;subtract first position move.l a0,d0 ;do NOT subtract, LF need this byte * setup start/end indices in Stream Control Block clr.l fh_Pos(REG_CIS) move.l d0,fh_End(REG_CIS) * misc setup clr.l pr_Result2(REG_Process) ;clear secondary result moveq #0,d0 move.l #SIGBREAKF_CTRL_C,d1 callsys SetSignal ;clear CTRL-C flag * handle seglist and start address move.l cli_Module(REG_CLI),sf_SaveModule(sp) move.l ARG_SEGLIST(REG_PrevStack),d0 ;second argument to "System0()" move.l d0,cli_Module(REG_CLI) lsl.l #2,d0 movea.l d0,a3 ;make it a machine pointer in A3 * setup processor registers & C-interface lea sf_CommandArgs(sp),a0 move.l fh_End(REG_CIS),d0 * setup processor registers, BCPL-interface, stack & return address for "Exit()" movea.l sf_StackBase(sp),a1 ;BCPL stack, low end move.l sf_PushSize(sp),d2 lea 4(a1,d2.l),a4 ;must not destroy REG_Process! move.l sp,-(a4) ;previous stack frame move.l d2,-(a4) ;stack size in bytes move.l a4,pr_ReturnAddr(REG_Process) movea.l a4,sp movea.l _DOSBase,a4 ;large data memory model! movem.l dl_A2(a4),a2/a5/a6 * now call the command at its entry point jsr 4(a3) ;code starts one longword behind segment pointer move.l d0,REG_Result ;save return code * get old stackframe & reload old register contents movea.l 4(sp),sp ;old stack frame movea.l sf_Process(sp),a0 move.l sf_SaveReturnAddr(sp),pr_ReturnAddr(a0) movea.l sf_CLI(sp),a0 move.l sf_SaveCommandName(sp),cli_CommandName(a0) move.l sf_SaveModule(sp),cli_Module(a0) * restore original contents of Current Input Stream movea.l sf_CIS(sp),a0 lea sf_CommandArgs(sp),a1 move.l a1,d0 lsr.l #2,d0 cmp.l fh_Buf(a0),d0 ;still the same? bne.s 5$ ;no: don't restore move.l sf_SCB_Buf(sp),fh_Buf(a0) 5$ move.l sf_SCB_Pos(sp),fh_Pos(a0) tst.l fh_End(a0) ;end index set? beq.s 6$ ;no: don't restore move.l sf_SCB_End(sp),fh_End(a0) * free temporary stack 6$ movea.l AbsExecBase,REG_SysBase movea.l sf_StackBase(sp),a1 move.l sf_StackSize(sp),d0 callsys FreeMem quit1 movea.l sf_PrevStack(sp),sp ;UNLINK local variables quit0 move.l REG_Result,d0 movem.l (sp)+,SAVED_REGS rts end ################ begin 777 System0.obj M```#YP````````/I````94CG,#YV_RQX``23R4ZN_MHD0"`J`*QG``%TY8@FN M0"I/(`\"``#\+D">_`(T+TT"`"]*`APO2P(@+VH`L`($=OX@*P`TY8@O0`(8- M6(`O0`(4<@!.KO\Z2H!G``$N+T`"$"]K`!`"#"!M`"!#[P`!(`GDB"=``!`PY M/`#_8`(2P1(85\C_^I'M`"`@"%.`'T```"`J`)SEB"A`+TP")"]L``P"*"]LR M`!`"+"]L`!0","!M`"A#[P$`(`GDB"E```PP/`#_8`(2P1(85\C_^A*\``J1< M[0`H(`A"K``0*4``%$*J`)1P`"(\```0`$ZN_LXO:P`\`@@@+0`D)T``/.6(_ M)D!![P$`("P`%")O`A`D+P(82?$H!"D/*0(E3`"P+DPH>0````!,[&0``"I.@ MJP`$)@`N;P`$(&\"'"%O`@0`L"!O`B`A;P(,`!`A;P((`#P@;P(D0^\!`"`)O MY(BPJ``,9@8A;P(H``PA;P(L`!!*J``49P8A;P(P`!0L>``$(F\"$"`O`A1.7 MKO\N+F\"`"`#3-]\#$YU```#[P$```)?4WES=&5M,`````"!```"7T1/4T)A' 2