home *** CD-ROM | disk | FTP | other *** search
- /* RexxFuncHost.c */
-
-
- /* Version 1.2 */
-
- /* Copyright © 1989 by Donald T. Meyer, Stormgate Software
- * All Rights Reserved
- *
- * This source code may be compiled and used in any software
- * product.
- * No portion of this source code is to be
- * re-distributed or sold for profit without the written
- * permission of the author, Donald T. Meyer.
- *
- * Stormgate Software
- * PO Box 383
- * St. Peters, MO 63376
- *
- * E-Mail can be sent to via the following:
- * BIX: donmeyer (almost daily)
- * GEnie: D.MEYER (weekly)
- * PLINK: Stormgate (weekly)
- */
-
-
-
- #include <exec/types.h>
- #include <libraries/dos.h>
- #include <workbench/startup.h>
-
- #include <proto/intuition.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- #include <string.h>
- #include <stdlib.h>
-
- #include "rexxfunchost.h"
-
-
-
- /*------------------------------------------------------------------*/
- /* External Function Declarations */
- /*------------------------------------------------------------------*/
-
- /* These are (better be!) in the user function module(s) */
-
- char *client_init( void );
-
- void client_cleanup( void );
-
- void client_event_handler( ULONG flags );
-
-
-
- /*------------------------------------------------------------------*/
- /* External Variable Declarations */
- /*------------------------------------------------------------------*/
-
-
- /* These are also in the user function module(s) */
-
- extern char *hello_string;
- extern char *success_string;
- extern char *removal_string;
- extern char *redundant_string;
- extern char *noclone_string;
-
- extern struct RexxFunction func_table[];
-
- extern int hostpri;
- extern char *hostname;
-
- extern BPTR _Backstdout;
- extern char *console_def_string;
-
- extern ULONG client_event_flags;
-
-
-
- /* Other misc. external variables. */
-
- extern struct WBStartup *WBenchMsg;
-
-
-
- /*------------------------------------------------------------------*/
- /* Local Function Declarations */
- /*------------------------------------------------------------------*/
-
- static void openlibrarys( void );
- static void closelibrarys( void );
-
- static void bailout( char *message, int rc );
-
- static void cleanup( void );
-
- static void init_port( void );
-
- static void eventloop( void );
-
- static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
- STRPTR arg3 );
-
- static void rexx_delete_port( struct MsgPort *port );
-
- static void check_result( struct Rexxmsg *rexxmsg );
-
- static void dispatch( struct RexxMsg *rexxmsg );
-
- static void check_clone( int argc, char *argv[] );
-
- static BOOL remove_clone( void );
-
-
-
- /*------------------------------------------------------------------*/
- /* Variable Definitions */
- /*------------------------------------------------------------------*/
-
- struct RxsLib *RexxSysBase = NULL;
-
-
- static struct MsgPort *hostport = NULL;
-
- static BPTR message_console = NULL;
-
- static BOOL finished = FALSE;
-
- static BOOL on_list = FALSE;
-
-
- /* For detaching */
- long _BackGroundIO = 1;
-
-
-
- /*------------------------------------------------------------------*/
- /* Functions */
- /*------------------------------------------------------------------*/
-
-
- void main( int argc, char *argv[] )
- {
- char *errmsg;
-
-
- if( _Backstdout == NULL )
- {
- /* Probably child of workbench, open our own window */
- /* Open a window to print hello and copyright stuff to */
- message_console = Open( console_def_string, MODE_NEWFILE );
-
- /* After some thought, I decided to quit if we could not
- * post our hello banner, etc.
- * We could just as easily continue, but this _should_ never
- * fail, so probably moot.
- */
- if( message_console == NULL )
- bailout( NULL, RETURN_FAIL );
- }
- else
- {
- /* Send banner and error messages to the CLI that started us */
- message_console = _Backstdout;
- }
-
- openlibrarys();
-
- Write( message_console, hello_string, strlen(hello_string) );
-
- check_clone( argc, argv );
-
- init_port();
-
- /* Allow the client to do his initializations */
- if( ( errmsg = client_init() ) != NULL )
- {
- bailout( errmsg, RETURN_FAIL );
- }
-
- Write( message_console, success_string, strlen(success_string) );
-
- /* Done with window, close it */
- Delay( 200 );
- Close( message_console );
- message_console = NULL;
-
- eventloop();
-
- cleanup();
-
- exit( RETURN_OK );
- }
-
-
-
- /* We come here after all of the initialization is done, and don't
- * leave until we receive a termination signal.
- */
-
- static void eventloop( void )
- {
- struct RexxMsg *rexxmsg;
- ULONG flags;
-
-
- while( ! finished )
- {
- flags = Wait( ( 1L<<hostport->mp_SigBit ) | SIGBREAKF_CTRL_C
- | client_event_flags );
-
- /* Call a routine in the client to allow any application-
- * specific things such as window events to be dealt with.
- */
- client_event_handler( flags );
-
- while( rexxmsg = (struct RexxMsg *)GetMsg( hostport ) )
- {
- if( IsRexxMsg(rexxmsg) )
- {
- /* The message is from an ARexx program */
-
- /* Handle the message contents */
-
- if( (rexxmsg->rm_Action & RXCODEMASK) == RXFUNC )
- {
- /* We only respond to function invocations, as
- * opposed to anything else (i.e. a command
- * invocation if our host port was set as the
- * ARexx address).
- */
- dispatch( rexxmsg );
-
- check_result( rexxmsg );
- }
- }
-
-
- /* We always reply, even if the message is not really
- * something we want to handle
- */
- ReplyMsg( (struct Message *)rexxmsg );
- }
-
-
- if( flags & SIGBREAKF_CTRL_C )
- {
- /* Somebody wants us to quit. Probably another us! */
- finished = TRUE;
- }
- }
- }
-
-
-
- /* This will take the function name from the RexxMsg and try to
- * find a function in our command table which matches. This is
- * also where the argument count verification is done.
- * If a function which matches is found, and it has the correct
- * number of arguments, it is vectored to.
- */
-
- static void dispatch( struct RexxMsg *rexxmsg )
- {
- int i, match = -1;
- char *cmd;
-
-
- cmd = ARG0(rexxmsg);
-
- for( i=0; func_table[i].fname != NULL; i++ )
- {
- if( func_table[i].caseflag == TRUE )
- {
- /* Case sensitive */
- if( strcmp( func_table[i].fname, cmd ) == 0 )
- {
- /* A match */
- match = i;
- break;
- }
- }
- else
- {
- /* Not case sensitive */
- if( stricmp( func_table[i].fname, cmd ) == 0 )
- {
- /* A match */
- match = i;
- break;
- }
- }
- }
-
- if( match == -1 )
- {
- /* No match found */
- rexxmsg->rm_Result1 = RC_WARN;
- rexxmsg->rm_Result2 = ERR10_001;
- return;
- }
-
- /* Found a match. Let's do the argument checking */
- if( ( func_table[match].argcount != -1 ) &&
- ( ( rexxmsg->rm_Action & RXARGMASK ) !=
- func_table[match].argcount ) )
- {
- /* Wrong number of args */
- rexxmsg->rm_Result1 = RC_ERROR;
- rexxmsg->rm_Result2 = ERR10_017;
- return;
- }
-
-
- /* Since we found a function, default to a "success" code. */
- rexxmsg->rm_Result1 = RC_OK;
- rexxmsg->rm_Result2 = 0;
-
- /* Call the function. */
- (*(func_table[match].func))(rexxmsg);
- }
-
-
-
- /* To ease the burden on a function, the checking for wether or not
- * an argstring was requested is done here. This will ensure that
- * one is never returned if ARexx did not ask for one.
- */
-
- static void check_result( struct RexxMsg *rexxmsg )
- {
- /* Make sure that we don't return an argstring
- * if one was not requested
- */
- if( rexxmsg->rm_Action & RXFF_RESULT )
- {
- /* Result string wanted */
- return;
- }
-
-
- /* A result string was not requested. Let's see if there is one */
-
- if( (rexxmsg->rm_Result1==0) && (rexxmsg->rm_Result2!=0) )
- {
- /* There is one, so we need to delete it. */
- DeleteArgstring( (struct RexxArg *)(rexxmsg->rm_Result2) );
- rexxmsg->rm_Result2 = 0;
- }
- }
-
-
-
- /* Open a public port and add it to the ARexx Library List. This is
- * where ARexx will send messages for functions it wants resolved.
- *
- * Note that we create our port with a priority higher than zero.
- * This should give a _very_slight_ increase in speed when ARexx
- * FindPort()'s us.
- */
-
- static void init_port( void )
- {
- /* Setup the public host port */
- if( ( hostport = CreatePort( hostname, 5 ) ) == NULL )
- {
- bailout( "Unable to create message port", RETURN_FAIL );
- }
-
- /* Add ourselves to the arexx library list */
- if( to_rexx( (ULONG)RXADDFH, hostname, (STRPTR)hostpri, NULL, NULL ) )
- {
- /* Could not add our port to the library list */
- bailout( "Unable to add self to ARexx library list",
- RETURN_FAIL );
- }
-
- on_list = TRUE;
- }
-
-
-
- /* This function does some fairly convoluted things involving
- * terminating another previously running invocation of ourselves.
- * Depending on wether we are launched from CLI or WorkBench and
- * command line options (only if from the CLI of course).
- * The logic is:
- *
- * IF from WorkBench
- * IF already invoked
- * remove existing invocation
- * exit
- *
- * IF from CLI
- * IF -q option
- * IF already invoked
- * remove existing invocation
- * exit
- * ELSE
- * tell user there is no existing invocation
- * exit
- * ELSE
- * IF already invoked
- * tell user that we cannot install again
- * exit
- *
- */
-
- static void check_clone( int argc, char *argv[] )
- {
- if( WBenchMsg )
- {
- /* We are running from workbench, see if we want to
- * kill off the existing invocation.
- */
- if( remove_clone() )
- {
- /* There was and we did */
- bailout( removal_string, RETURN_OK );
- }
- /* Else, there was no clone, continue execution. */
- }
- else
- {
- /* From the CLI. If the argument "-q" is given, we try to kill
- * the existing invocation. Otherwise we just refuse
- * to start another invocation.
- */
- if( ( argc > 1 ) && ( stricmp(argv[1],"-q") == 0 ) )
- {
- /* User wants us to remove ourselves */
- if( remove_clone() )
- {
- /* There was and we did */
- bailout( removal_string, RETURN_OK );
- }
- else
- {
- /* There was no previous invocation */
- bailout( noclone_string, RETURN_WARN );
- }
- }
- else
- {
- /* The user is trying to invoke us. */
- if( FindPort( hostname ) )
- {
- /* But we already exist */
- bailout( redundant_string, RETURN_WARN );
- }
- }
- }
- }
-
-
-
- /* If there is already another instance of ourselves running, kill it
- * and return TRUE, otherwise return FALSE.
- */
-
- static BOOL remove_clone( void )
- {
- struct MsgPort *otherport;
-
-
- if( ( otherport = FindPort( hostname ) ) != NULL )
- {
- /* Yes, we are */
- Signal( otherport->mp_SigTask, SIGBREAKF_CTRL_C );
- return( TRUE );
- }
-
- return( FALSE );
- }
-
-
-
- /* Open any librarys needed. In this case, just one. The client
- * modules may also open additional librarys as needed of course.
- */
-
- static void openlibrarys( void )
- {
- /* ARexx library */
- if( ! ( RexxSysBase = (struct RxsLib *)OpenLibrary( RXSNAME, 0L) ) )
- {
- bailout( "Unable to open the ARexx Library", RETURN_FAIL );
- }
- }
-
-
-
- /* Complement to openlibrarys()
- */
-
- static void closelibrarys( void )
- {
- if( RexxSysBase )
- CloseLibrary( (struct Library *)RexxSysBase );
- }
-
-
-
- /* This routine will do everything neccessary to see that we make an
- * orderly exit, regardless of what point in the program we were at.
- */
-
- static void cleanup( void )
- {
- client_cleanup();
-
- if( on_list == TRUE )
- {
- /* Remove ourselves from the arexx library list */
- to_rexx( (ULONG)RXREMLIB, hostname, NULL, NULL, NULL );
- }
-
- if( hostport )
- {
- rexx_delete_port( hostport );
- }
-
- closelibrarys();
-
- if( message_console )
- {
- Close( message_console );
- }
- }
-
-
-
- /* Typicaly the place we come when something has gone awry, although
- * some fairly innocous events (like already being installed) will
- * call this also as their way out.
- * If there is a message, and a way to display it, it will be displayed.
- * Then free any resources, and exit!
- */
-
- static void bailout( char *message, int rc )
- {
- if( message_console && message )
- {
- Write( message_console, message, strlen(message) );
- Delay( 200 );
- }
-
- cleanup();
-
- exit( rc );
- }
-
-
-
- /* General purpose utility function to send messages to the ARexx
- * resident process. For simplicity's sake, we ask ARexx to not
- * respond. This does mean that a request could fail and we would
- * never know. Since there is _very_ little reason for anything
- * we are doing here to fail, it seems a reasonable risk. Else
- * why would Bill have given us the RXFB_NONRET flag? :-)
- */
-
- static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
- STRPTR arg3 )
- {
- struct MsgPort *rmast;
- struct RexxMsg *rexxmsg;
-
-
- /* Allocate a packet to send to rexxmaster */
- rexxmsg = CreateRexxMsg( NULL, NULL, NULL );
- if( rexxmsg == NULL )
- {
- return( 1 );
- }
-
- rexxmsg->rm_Action = cmd | RXFF_NONRET;
-
- rexxmsg->rm_Args[0] = arg0;
- rexxmsg->rm_Args[1] = arg1;
- rexxmsg->rm_Args[2] = arg2;
- rexxmsg->rm_Args[3] = arg3;
-
- Forbid();
- if( rmast = FindPort( "REXX" ) )
- {
- PutMsg( rmast, (struct Message *)rexxmsg );
- }
- Permit();
-
- if( rmast == NULL )
- {
- /* we could not find the REXX port, this failed! */
- DeleteRexxMsg( rexxmsg );
- return( 2 );
- }
-
- return( 0 );
- }
-
-
-
- /* This will safely delete a message port used to recieve commands
- * from ARexx.
- * This is acomplished by setting a failure return code and replying the
- * message if it is from ARexx. If the message is not from ARexx, it
- * is merely replied.
- *
- * The Forbid() Permit() bracketing is done to insure that the port
- * is empty when we delete it. It would be *very* rude to cause
- * the ARexx resident process to hang waiting for us to reply a
- * message that we never will...
- */
-
- static void rexx_delete_port( struct MsgPort *port )
- {
- struct RexxMsg *rexxmsg;
-
-
- Forbid();
-
- while( rexxmsg = (struct RexxMsg *)GetMsg( port ) )
- {
- if( IsRexxMsg( rexxmsg ) )
- {
- /* Set failure code */
- rexxmsg->rm_Result1 = RC_ERROR;
- rexxmsg->rm_Result2 = ERR10_015;
- }
-
- ReplyMsg( (struct Message *)rexxmsg );
- }
-
- DeletePort( port );
-
- Permit();
- }
-
-
-
- /* This can be called to handle the details of placing a result
- * string into the rexx message packet as the result Argstring.
- * This will deal with inability to allocate the Argstring.
- * If the string pointer is NULL, a general failure code will
- * be set.
- */
-
- void SetResultString( struct RexxMsg *rexxmsg, char *string )
- {
- if( string )
- {
- rexxmsg->rm_Result1 = RC_OK;
- rexxmsg->rm_Result2 =
- (ULONG)CreateArgstring( string, strlen(string) );
-
- if( rexxmsg->rm_Result2 == NULL )
- {
- /* Unable to create the argstring */
- rexxmsg->rm_Result1 = RC_ERROR;
- rexxmsg->rm_Result2 = ERR10_012;
- }
- }
- else
- {
- /* Result string is null, set general failure code */
- rexxmsg->rm_Result1 = RC_ERROR;
- rexxmsg->rm_Result2 = ERR10_012;
- }
- }
-
-