home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Launch.c
- **
- ** Routines to launch programs, ARexx scripts, etc.
- **
- ** Copyright © 1990-1996 by Olaf `Olsen' Barthel
- ** All Rights Reserved
- **
- ** :ts=4
- */
-
- #ifndef _GLOBAL_H
- #include "Global.h"
- #endif
-
- /* Local data. */
-
- STATIC struct SignalSemaphore LaunchSemaphore;
- STATIC LONG LaunchCounter;
-
- STATIC BOOL
- OpenStreams(STRPTR StreamName,BPTR *InputStream,BPTR *OutputStream)
- {
- BPTR Stream;
-
- /* Open the output stream. */
-
- if(Stream = Open(StreamName,MODE_NEWFILE))
- {
- /* Check if the stream is not "NIL:" and if it is interactive. */
-
- if(GoodStream(Stream))
- {
- *InputStream = Stream;
- *OutputStream = NULL;
- }
- else
- {
- *InputStream = Open("NIL:",MODE_NEWFILE);
- *OutputStream = Stream;
- }
-
- if(*InputStream)
- return(TRUE);
- else
- {
- LONG Error = IoErr();
-
- Close(Stream);
-
- SetIoErr(Error);
- }
- }
-
- return(FALSE);
- }
-
- /* LaunchEntry(VOID):
- *
- * Entry point of the routine that handles the workload.
- */
-
- STATIC VOID SAVE_DS
- LaunchEntry(VOID)
- {
- LaunchMsg *Startup;
- struct MsgPort *CurrentPort;
- BPTR InputStream,OutputStream;
- struct MsgPort *GlobalRexxPort;
-
- /* Grab the startup packet. */
-
- CurrentPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
- WaitPort(CurrentPort);
- Startup = (LaunchMsg *)GetMsg(CurrentPort);
-
- /* Increment the launch counter. */
-
- ObtainSemaphore(&LaunchSemaphore);
- LaunchCounter++;
- ReleaseSemaphore(&LaunchSemaphore);
-
- /* Open the streams. */
-
- InputStream = OutputStream = NULL;
-
- if(!OpenStreams(Startup->Message.mn_Node.ln_Name,&InputStream,&OutputStream))
- Startup->Result2 = IoErr();
- else
- {
- if(!OutputStream)
- {
- SelectInput(InputStream);
-
- SetConsoleTask(((struct FileHandle *)BADDR(InputStream))->fh_Type);
-
- if(!(OutputStream = Open("CONSOLE:",MODE_NEWFILE)))
- Startup->Result2 = IoErr();
- }
- }
-
- if(InputStream && OutputStream)
- {
- SelectOutput(OutputStream);
-
- Forbid();
-
- /* Try to find the global Rexx port. */
-
- if(!(GlobalRexxPort = FindPort(RXSDIR)))
- Startup->Result2 = ERROR_OBJECT_NOT_FOUND;
- else
- {
- struct MsgPort SinglePort;
- struct RexxMsg *RexxMsg;
-
- /* Set up our local msgport. */
-
- InitSinglePort(&SinglePort);
-
- /* Create a message for Rexx. */
-
- if(RexxMsg = CreateRexxMsg(&SinglePort,"term",RexxPortName))
- {
- /* And put in the command to execute. */
-
- if(RexxMsg->rm_Args[0] = CreateArgstring(Startup->Command,strlen(Startup->Command)))
- {
- /* Flag the message as a command to be executed. */
-
- RexxMsg->rm_Action = RXCOMM;
-
- /* In case it's just a single string, flag it as being such. */
-
- if(Startup->Type == LAUNCH_RexxString)
- RexxMsg->rm_Action |= RXFF_STRING;
-
- /* Clear the port mask. */
-
- SetSignal(0,SIGF_SINGLE);
-
- /* Send the message and wait for it to return.
- * Notice that after the WaitPort() call we
- * won't call GetMsg() since we don't need the
- * msgport any more and don't expect more than
- * one message to end up here.
- */
-
- PutMsg(GlobalRexxPort,(struct Message *)RexxMsg);
- WaitPort(&SinglePort);
-
- /* Store the command result. */
-
- Startup->Result = RexxMsg->rm_Result1;
- Startup->Result2 = RexxMsg->rm_Result2;
-
- /* And clean up the rest. */
-
- DeleteArgstring(RexxMsg->rm_Args[0]);
- }
- else
- Startup->Result2 = ERROR_NO_FREE_STORE;
-
- DeleteRexxMsg(RexxMsg);
- }
- else
- Startup->Result2 = ERROR_NO_FREE_STORE;
- }
-
- Permit();
- }
-
- /* Call the cleanup routine if any. */
-
- if(Startup->Cleanup)
- (*Startup->Cleanup)(Startup);
-
- /* Close the streams. */
-
- if(InputStream)
- Close(InputStream);
-
- if(OutputStream)
- Close(OutputStream);
-
- /* Decrement the launch counter and disable
- * multitasking for a short while.
- */
-
- ObtainSemaphore(&LaunchSemaphore);
-
- LaunchCounter--;
-
- Forbid();
-
- /* Check if we should wake up the process that
- * created us. If not, dispose of the startup
- * message.
- */
-
- if(Startup->Message.mn_ReplyPort != NULL)
- ReplyMsg((struct Message *)Startup);
- else
- DeleteLaunchMsg(Startup);
-
- /* Release the launch counter semaphore and exit. */
-
- ReleaseSemaphore(&LaunchSemaphore);
- }
-
- /* CreateLaunchMsg(WORD Type,STRPTR Command,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup):
- *
- * This sets up a launch message with given parameters.
- */
-
- STATIC LaunchMsg *
- CreateLaunchMsg(WORD Type,STRPTR Command,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup)
- {
- LaunchMsg *Startup;
-
- /* Allocate memory for the data structure and initialize it. */
-
- if(Startup = (LaunchMsg *)AllocVecPooled(sizeof(LaunchMsg) + strlen(Command) + 1,MEMF_ANY|MEMF_CLEAR))
- {
- Startup->Message.mn_Length = sizeof(LaunchMsg) + strlen(Command);
- Startup->Type = Type;
- Startup->RexxPkt = RexxPkt;
- Startup->Cleanup = Cleanup;
-
- strcpy(Startup->Command,Command);
- }
-
- return(Startup);
- }
-
- /* DeleteLaunchMsg(LaunchMsg *Startup):
- *
- * Releases all the memory allocated for the launch message.
- */
-
- VOID
- DeleteLaunchMsg(LaunchMsg *Startup)
- {
- if(Startup->Message.mn_Node.ln_Name)
- FreeVecPooled(Startup->Message.mn_Node.ln_Name);
-
- FreeVecPooled(Startup);
- }
-
- /* CreateRexxCmdLaunchMsg():
- *
- * Creates a special type of launch message for use with Rexx commands.
- */
-
- LaunchMsg *
- CreateRexxCmdLaunchMsg(STRPTR RexxCmd,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup)
- {
- return(CreateLaunchMsg(LAUNCH_RexxCmd,RexxCmd,RexxPkt,Cleanup));
- }
-
- /* CreateProgramLaunchMsg():
- *
- * Creates a special type of launch message for use with AmigaDOS commands.
- */
-
- LaunchMsg *
- CreateProgramLaunchMsg(STRPTR Program,LAUNCHCLEANUP Cleanup)
- {
- return(CreateLaunchMsg(LAUNCH_Program,Program,NULL,Cleanup));
- }
-
- /* LaunchSomething(STRPTR OriginalStreamName,BOOL Synchronous,LaunchMsg *Startup):
- *
- * Launch a program either in synchronous or asynchronous fashion, using
- * a given output stream. If no stream name is given, "NIL:" will be used.
- */
-
- LONG
- LaunchSomething(STRPTR OriginalStreamName,BOOL Synchronous,LaunchMsg *Startup)
- {
- BPTR InputStream,OutputStream;
- BOOL InsertScreenName;
- LONG Result,Error;
- STRPTR StreamName;
- LONG i,Head;
-
- /* Did we get a name? If not, use "NIL:". */
-
- if(!OriginalStreamName)
- OriginalStreamName = "NIL:";
- else
- {
- /* Is the string empty? If so, use "NIL:". */
-
- if(!OriginalStreamName[0])
- OriginalStreamName = "NIL:";
- }
-
- /* Scan the stream name for "%s" which will be replaced by the
- * name of the public screen `term' is using.
- */
-
- for(i = 0, InsertScreenName = FALSE, Head = 0 ; i < strlen(OriginalStreamName) - 1 ; i++)
- {
- if(OriginalStreamName[i] == '%' && OriginalStreamName[i+1] == 's')
- {
- Head = i;
-
- InsertScreenName = TRUE;
- break;
- }
- }
-
- /* Should we insert a public screen name somewhere? */
-
- if(InsertScreenName)
- {
- UBYTE ScreenName[MAXPUBSCREENNAME + 1];
-
- /* Get the name of the current default public screen. */
-
- GetDefaultPubScreen(ScreenName);
-
- /* If the screen `term' has its main window on is on a
- * public screen, get the name of this screen. Otherwise,
- * don't touch the buffer contents.
- */
-
- if(Window)
- GetPubScreenName(Window->WScreen,ScreenName);
-
- /* Make room for the screen name. */
-
- if(!(StreamName = (STRPTR)AllocVecPooled(strlen(ScreenName) + strlen(OriginalStreamName) - 1,MEMF_ANY)))
- {
- SetIoErr(ERROR_NO_FREE_STORE);
-
- return(FALSE);
- }
-
- /* Insert the screen name into the stream name. */
-
- if(Head > 0)
- strncpy(StreamName,OriginalStreamName,Head);
-
- StreamName[Head] = 0;
-
- strcat(StreamName,ScreenName);
- strcat(StreamName,&OriginalStreamName[Head + 2]);
- }
- else
- StreamName = OriginalStreamName;
-
- /* Reset these. */
-
- Result = Error = 0;
-
- InputStream = OutputStream = NULL;
-
- if(Startup->Type == LAUNCH_Program)
- {
- if(!OpenStreams(StreamName,&InputStream,&OutputStream))
- Error = IoErr();
- else
- {
- if(Result = SystemTags(Startup->Command,
- SYS_Input, InputStream,
- SYS_Output, OutputStream,
- SYS_Asynch, Synchronous == FALSE,
- SYS_UserShell, TRUE,
- NP_StackSize, 8000,
- TAG_DONE))
- Error = IoErr();
-
- /* These will be closed when the program
- * launched will exit.
- */
-
- if(Synchronous == FALSE)
- InputStream = OutputStream = NULL;
- }
-
- Startup->Result = Result;
- Startup->Result2 = Error;
- }
- else
- {
- if(!(Startup->Message.mn_Node.ln_Name = (char *)AllocVecPooled(strlen(StreamName) + 1,MEMF_ANY)))
- Error = IoErr();
- else
- {
- /* The default process launch tags. */
-
- STATIC struct TagItem DefaultTags[] =
- {
- NP_Entry, (ULONG)LaunchEntry,
- NP_StackSize, 8000,
- NP_Name, (ULONG)"term Child Process",
- NP_Cli, TRUE,
- NP_Input, NULL,
- NP_Output, NULL,
- NP_CloseInput, FALSE,
- NP_CloseOutput, FALSE,
-
- TAG_DONE
- };
-
- struct Process *Child;
-
- /* Keep the stream name. */
-
- strcpy(Startup->Message.mn_Node.ln_Name,StreamName);
-
- /* Launch the child process. */
-
- if(!(Child = CreateNewProc(DefaultTags)))
- {
- Result = RETURN_FAIL;
- Error = IoErr();
- }
- else
- {
- /* If the command is to be executed in asynchronous
- * fashion, just send the message. The child process
- * will clean up all on its own.
- */
-
- if(Synchronous == FALSE)
- PutMsg(&Child->pr_MsgPort,(struct Message *)Startup);
- else
- {
- struct MsgPort SinglePort;
-
- /* Set up the local msgport. */
-
- InitSinglePort(&SinglePort);
-
- /* Clear the port signal. */
-
- SetSignal(0,SIGF_SINGLE);
-
- /* Fill in the reply port. */
-
- Startup->Message.mn_ReplyPort = &SinglePort;
-
- /* Send the startup message and wait for the
- * reply. Note that we don't GetMsg() the
- * message we sent since the local msgport
- * will be discarded anyway.
- */
-
- PutMsg(&Child->pr_MsgPort,(struct Message *)Startup);
- WaitPort(&SinglePort);
-
- /* Copy the result data. */
-
- Result = Startup->Result;
- Error = Startup->Result2;
- }
- }
- }
- }
-
- /* Do the cleanup. */
-
- if(Synchronous)
- {
- Startup->Result = Result;
- Startup->Result2 = Error;
- }
-
- if(Startup->Cleanup)
- (*Startup->Cleanup)(Startup);
-
- if(Synchronous)
- DeleteLaunchMsg(Startup);
-
- /* Close the streams still open. */
-
- if(InputStream)
- Close(InputStream);
-
- if(OutputStream)
- Close(OutputStream);
-
- /* If we had allocated a new stream name, release the memory. */
-
- if(StreamName != OriginalStreamName)
- FreeVecPooled(StreamName);
-
- SetIoErr(Error);
-
- return(Result);
- }
-
- /* LaunchSetup():
- *
- * Does the setup operation for the launch procedure.
- */
-
- VOID
- LaunchSetup()
- {
- InitSemaphore(&LaunchSemaphore);
- }
-
- /* GetLaunchCounter():
- *
- * Returns the number of processes launched that haven't
- * returned already.
- */
-
- LONG
- GetLaunchCounter()
- {
- LONG Counter;
-
- SafeObtainSemaphoreShared(&LaunchSemaphore);
-
- Counter = LaunchCounter;
-
- ReleaseSemaphore(&LaunchSemaphore);
-
- return(Counter);
- }
-