home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 291.lha / RexxFunctionHostPack_v1.2 / rexxfunchost.c < prev    next >
C/C++ Source or Header  |  1992-09-02  |  14KB  |  672 lines

  1. /*  RexxFuncHost.c   */
  2.  
  3.  
  4. /* Version 1.2 */
  5.  
  6. /*        Copyright © 1989 by Donald T. Meyer, Stormgate Software
  7.  *        All Rights Reserved
  8.  *
  9.  *        This source code may be compiled and used in any software
  10.  *        product.
  11.  *        No portion of this source code is to be
  12.  *        re-distributed or sold for profit without the written
  13.  *        permission of the author, Donald T. Meyer.
  14.  *
  15.  *        Stormgate Software
  16.  *        PO Box 383
  17.  *        St. Peters, MO  63376
  18.  *
  19.  *        E-Mail can be sent to via the following:
  20.  *        BIX:    donmeyer        (almost daily)
  21.  *        GEnie:    D.MEYER            (weekly)
  22.  *        PLINK:    Stormgate        (weekly)
  23.  */
  24.  
  25.  
  26.  
  27. #include <exec/types.h>
  28. #include <libraries/dos.h>
  29. #include <workbench/startup.h>
  30.  
  31. #include <proto/intuition.h>
  32. #include <proto/exec.h>
  33. #include <proto/dos.h>
  34.  
  35. #include <string.h>
  36. #include <stdlib.h>
  37.  
  38. #include "rexxfunchost.h"
  39.  
  40.  
  41.  
  42. /*------------------------------------------------------------------*/
  43. /*                    External Function Declarations                    */
  44. /*------------------------------------------------------------------*/
  45.  
  46. /* These are (better be!) in the user function module(s) */
  47.  
  48. char *client_init( void );
  49.  
  50. void client_cleanup( void );
  51.  
  52. void client_event_handler( ULONG flags );
  53.  
  54.  
  55.  
  56. /*------------------------------------------------------------------*/
  57. /*                    External Variable Declarations                    */
  58. /*------------------------------------------------------------------*/
  59.  
  60.  
  61. /* These are also in the user function module(s) */
  62.  
  63. extern char *hello_string;
  64. extern char *success_string;
  65. extern char *removal_string;
  66. extern char *redundant_string;
  67. extern char *noclone_string;
  68.  
  69. extern struct RexxFunction func_table[];
  70.  
  71. extern int hostpri;
  72. extern char *hostname;
  73.  
  74. extern BPTR _Backstdout;
  75. extern char *console_def_string;
  76.  
  77. extern ULONG client_event_flags;
  78.  
  79.  
  80.  
  81. /* Other misc. external variables. */
  82.  
  83. extern struct WBStartup *WBenchMsg;
  84.  
  85.  
  86.  
  87. /*------------------------------------------------------------------*/
  88. /*                    Local Function Declarations                        */
  89. /*------------------------------------------------------------------*/
  90.  
  91. static void openlibrarys( void );
  92. static void closelibrarys( void );
  93.  
  94. static void bailout( char *message, int rc );
  95.  
  96. static void cleanup( void );
  97.  
  98. static void init_port( void );
  99.  
  100. static void eventloop( void );
  101.  
  102. static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
  103.     STRPTR arg3 );
  104.  
  105. static void rexx_delete_port( struct MsgPort *port );
  106.  
  107. static void check_result( struct Rexxmsg *rexxmsg );
  108.  
  109. static void dispatch( struct RexxMsg *rexxmsg );
  110.  
  111. static void check_clone( int argc, char *argv[] );
  112.  
  113. static BOOL remove_clone( void );
  114.  
  115.  
  116.  
  117. /*------------------------------------------------------------------*/
  118. /*                    Variable Definitions                            */
  119. /*------------------------------------------------------------------*/
  120.  
  121. struct RxsLib *RexxSysBase = NULL;
  122.  
  123.  
  124. static struct MsgPort *hostport = NULL;
  125.  
  126. static BPTR message_console = NULL;
  127.  
  128. static BOOL finished = FALSE;
  129.  
  130. static BOOL on_list = FALSE;
  131.  
  132.  
  133. /* For detaching */
  134. long _BackGroundIO = 1;
  135.  
  136.  
  137.  
  138. /*------------------------------------------------------------------*/
  139. /*                    Functions                                        */
  140. /*------------------------------------------------------------------*/
  141.  
  142.  
  143. void main( int argc, char *argv[] )
  144. {
  145.     char *errmsg;
  146.  
  147.  
  148.     if( _Backstdout == NULL )
  149.     {
  150.         /* Probably child of workbench, open our own window */
  151.         /* Open a window to print hello and copyright stuff to */
  152.         message_console = Open( console_def_string, MODE_NEWFILE );
  153.  
  154.         /* After some thought, I decided to quit if we could not
  155.          * post our hello banner, etc.
  156.          * We could just as easily continue, but this _should_ never
  157.          * fail, so probably moot.
  158.          */
  159.         if( message_console == NULL )
  160.             bailout( NULL, RETURN_FAIL );
  161.     }
  162.     else
  163.     {
  164.         /* Send banner and error messages to the CLI that started us */
  165.         message_console = _Backstdout;
  166.     }
  167.  
  168.     openlibrarys();
  169.  
  170.     Write( message_console, hello_string, strlen(hello_string) );
  171.  
  172.     check_clone( argc, argv );
  173.  
  174.     init_port();
  175.  
  176.     /* Allow the client to do his initializations */
  177.     if(  ( errmsg = client_init() ) != NULL  )
  178.     {
  179.         bailout( errmsg, RETURN_FAIL );
  180.     }
  181.  
  182.     Write( message_console, success_string, strlen(success_string) );
  183.  
  184.     /* Done with window, close it */
  185.     Delay( 200 );
  186.     Close( message_console );
  187.     message_console = NULL;
  188.  
  189.     eventloop();
  190.  
  191.     cleanup();
  192.  
  193.     exit( RETURN_OK );
  194. }
  195.  
  196.  
  197.  
  198. /* We come here after all of the initialization is done, and don't
  199.  * leave until we receive a termination signal.
  200.  */
  201.  
  202. static void eventloop( void )
  203. {
  204.     struct RexxMsg *rexxmsg;
  205.     ULONG flags;
  206.  
  207.  
  208.     while( ! finished )
  209.     {
  210.         flags = Wait(  ( 1L<<hostport->mp_SigBit ) | SIGBREAKF_CTRL_C
  211.             | client_event_flags  );
  212.  
  213.         /* Call a routine in the client to allow any application-
  214.          * specific things such as window events to be dealt with.
  215.          */
  216.         client_event_handler( flags );
  217.  
  218.         while( rexxmsg = (struct RexxMsg *)GetMsg( hostport ) )
  219.         {
  220.             if( IsRexxMsg(rexxmsg) )
  221.             {
  222.                 /* The message is from an ARexx program */
  223.  
  224.                 /* Handle the message contents */
  225.  
  226.                 if(  (rexxmsg->rm_Action & RXCODEMASK) == RXFUNC  )
  227.                 {
  228.                     /* We only respond to function invocations, as
  229.                      * opposed to anything else (i.e. a command
  230.                      * invocation if our host port was set as the
  231.                      * ARexx address).
  232.                      */
  233.                     dispatch( rexxmsg );
  234.  
  235.                     check_result( rexxmsg );
  236.                 }
  237.             }
  238.  
  239.  
  240.             /* We always reply, even if the message is not really
  241.              * something we want to handle
  242.              */
  243.             ReplyMsg( (struct Message *)rexxmsg );
  244.         }
  245.  
  246.  
  247.         if( flags & SIGBREAKF_CTRL_C )
  248.         {
  249.             /* Somebody wants us to quit.  Probably another us! */
  250.             finished = TRUE;
  251.         }
  252.     }
  253. }
  254.  
  255.  
  256.  
  257. /* This will take the function name from the RexxMsg and try to
  258.  * find a function in our command table which matches.  This is
  259.  * also where the argument count verification is done.
  260.  * If a function which matches is found, and it has the correct
  261.  * number of arguments, it is vectored to.
  262.  */
  263.  
  264. static void dispatch( struct RexxMsg *rexxmsg )
  265. {
  266.     int i, match = -1;
  267.     char *cmd;
  268.  
  269.  
  270.     cmd = ARG0(rexxmsg);
  271.  
  272.     for( i=0; func_table[i].fname != NULL; i++ )
  273.     {
  274.         if( func_table[i].caseflag == TRUE )
  275.         {
  276.             /* Case sensitive */
  277.             if(  strcmp( func_table[i].fname, cmd ) == 0  )
  278.             {
  279.                 /* A match */
  280.                 match = i;
  281.                 break;
  282.             }
  283.         }
  284.         else
  285.         {
  286.             /* Not case sensitive */
  287.             if(  stricmp( func_table[i].fname, cmd ) == 0  )
  288.             {
  289.                 /* A match */
  290.                 match = i;
  291.                 break;
  292.             }
  293.         }
  294.     }
  295.  
  296.     if( match == -1 )
  297.     {
  298.         /* No match found */
  299.         rexxmsg->rm_Result1 = RC_WARN;
  300.         rexxmsg->rm_Result2 = ERR10_001;
  301.         return;
  302.     }
  303.  
  304.     /* Found a match.  Let's do the argument checking */
  305.     if(   ( func_table[match].argcount != -1 ) &&
  306.         (  ( rexxmsg->rm_Action & RXARGMASK ) !=
  307.         func_table[match].argcount  )   )
  308.     {
  309.         /* Wrong number of args */
  310.         rexxmsg->rm_Result1 = RC_ERROR;
  311.         rexxmsg->rm_Result2 = ERR10_017;
  312.         return;
  313.     }
  314.  
  315.  
  316.     /* Since we found a function, default to a "success" code. */
  317.     rexxmsg->rm_Result1 = RC_OK;
  318.     rexxmsg->rm_Result2 = 0;
  319.  
  320.     /* Call the function. */
  321.     (*(func_table[match].func))(rexxmsg);
  322. }
  323.  
  324.  
  325.  
  326. /* To ease the burden on a function, the checking for wether or not
  327.  * an argstring was requested is done here.  This will ensure that
  328.  * one is never returned if ARexx did not ask for one.
  329.  */
  330.  
  331. static void check_result( struct RexxMsg *rexxmsg )
  332. {
  333.     /* Make sure that we don't return an argstring
  334.      * if one was not requested
  335.      */
  336.     if( rexxmsg->rm_Action & RXFF_RESULT )
  337.     {
  338.         /* Result string wanted */
  339.         return;
  340.     }
  341.  
  342.  
  343.     /* A result string was not requested.  Let's see if there is one */
  344.  
  345.     if( (rexxmsg->rm_Result1==0) && (rexxmsg->rm_Result2!=0) )
  346.     {
  347.         /* There is one, so we need to delete it. */
  348.         DeleteArgstring( (struct RexxArg *)(rexxmsg->rm_Result2) );
  349.         rexxmsg->rm_Result2 = 0;
  350.     }
  351. }
  352.  
  353.  
  354.  
  355. /* Open a public port and add it to the ARexx Library List.  This is
  356.  * where ARexx will send messages for functions it wants resolved.
  357.  *
  358.  * Note that we create our port with a priority higher than zero.
  359.  * This should give a _very_slight_ increase in speed when ARexx
  360.  * FindPort()'s us.
  361.  */
  362.  
  363. static void init_port( void )
  364. {
  365.     /* Setup the public host port */
  366.     if(  ( hostport = CreatePort( hostname, 5 ) ) == NULL  )
  367.     {
  368.         bailout( "Unable to create message port", RETURN_FAIL );
  369.     }
  370.  
  371.     /* Add ourselves to the arexx library list */
  372.     if( to_rexx( (ULONG)RXADDFH, hostname, (STRPTR)hostpri, NULL, NULL )  )
  373.     {
  374.         /* Could not add our port to the library list */
  375.         bailout( "Unable to add self to ARexx library list",
  376.             RETURN_FAIL );
  377.     }
  378.  
  379.     on_list = TRUE;
  380. }
  381.  
  382.  
  383.  
  384. /* This function does some fairly convoluted things involving
  385.  * terminating another previously running invocation of ourselves.
  386.  * Depending on wether we are launched from CLI or WorkBench and
  387.  * command line options (only if from the CLI of course).
  388.  * The logic is:
  389.  *
  390.  *        IF from WorkBench
  391.  *            IF already invoked
  392.  *                remove existing invocation
  393.  *                exit
  394.  *
  395.  *        IF from CLI
  396.  *            IF -q option
  397.  *                IF already invoked
  398.  *                    remove existing invocation
  399.  *                    exit
  400.  *                ELSE
  401.  *                    tell user there is no existing invocation
  402.  *                    exit
  403.  *            ELSE
  404.  *                IF already invoked
  405.  *                    tell user that we cannot install again
  406.  *                    exit
  407.  *
  408.  */
  409.  
  410. static void check_clone( int argc, char *argv[] )
  411. {
  412.     if( WBenchMsg )
  413.     {
  414.         /* We are running from workbench, see if we want to
  415.          * kill off the existing invocation.
  416.          */
  417.         if( remove_clone() )
  418.         {
  419.             /* There was and we did */
  420.             bailout( removal_string, RETURN_OK );
  421.         }
  422.             /* Else, there was no clone, continue execution. */ 
  423.     }
  424.     else
  425.     {
  426.         /* From the CLI.  If the argument "-q" is given, we try to kill
  427.          * the existing invocation.  Otherwise we just refuse
  428.          * to start another invocation.
  429.          */
  430.         if(  ( argc > 1 ) && ( stricmp(argv[1],"-q") == 0 )  )
  431.         {
  432.             /* User wants us to remove ourselves */
  433.             if( remove_clone() )
  434.             {
  435.                 /* There was and we did */
  436.                 bailout( removal_string, RETURN_OK );
  437.             }
  438.             else
  439.             {
  440.                 /* There was no previous invocation */
  441.                 bailout( noclone_string, RETURN_WARN );
  442.             }
  443.         }
  444.         else
  445.         {
  446.             /* The user is trying to invoke us. */
  447.             if(  FindPort( hostname )  )
  448.             {
  449.                 /* But we already exist */
  450.                 bailout( redundant_string, RETURN_WARN );
  451.             }
  452.         }
  453.     }
  454. }
  455.  
  456.  
  457.  
  458. /* If there is already another instance of ourselves running, kill it
  459.  * and return TRUE, otherwise return FALSE.
  460.  */
  461.  
  462. static BOOL remove_clone( void )
  463. {
  464.     struct MsgPort *otherport;
  465.  
  466.  
  467.     if(   (  otherport = FindPort( hostname )  ) != NULL  )
  468.     {
  469.         /* Yes, we are */
  470.         Signal( otherport->mp_SigTask, SIGBREAKF_CTRL_C );
  471.         return( TRUE );
  472.     }
  473.  
  474.     return( FALSE );
  475. }
  476.  
  477.  
  478.  
  479. /* Open any librarys needed.  In this case, just one.  The client
  480.  * modules may also open additional librarys as needed of course.
  481.  */
  482.  
  483. static void openlibrarys( void )
  484. {
  485.     /*   ARexx library   */
  486.     if(  ! ( RexxSysBase = (struct RxsLib *)OpenLibrary( RXSNAME, 0L) )  )
  487.     {
  488.         bailout( "Unable to open the ARexx Library", RETURN_FAIL );
  489.     }
  490. }
  491.  
  492.  
  493.  
  494. /* Complement to openlibrarys()
  495.  */
  496.  
  497. static void closelibrarys( void )
  498. {
  499.     if( RexxSysBase )
  500.         CloseLibrary( (struct Library *)RexxSysBase );
  501. }
  502.  
  503.  
  504.  
  505. /* This routine will do everything neccessary to see that we make an
  506.  * orderly exit, regardless of what point in the program we were at.
  507.  */
  508.  
  509. static void cleanup( void )
  510. {
  511.     client_cleanup();
  512.  
  513.     if( on_list == TRUE )
  514.     {
  515.         /* Remove ourselves from the arexx library list */
  516.         to_rexx( (ULONG)RXREMLIB, hostname, NULL, NULL, NULL );
  517.     }
  518.  
  519.     if( hostport )
  520.     {
  521.         rexx_delete_port( hostport );
  522.     }
  523.  
  524.     closelibrarys();
  525.  
  526.     if( message_console )
  527.     {
  528.         Close( message_console );
  529.     }
  530. }
  531.  
  532.  
  533.  
  534. /* Typicaly the place we come when something has gone awry, although
  535.  * some fairly innocous events (like already being installed) will
  536.  * call this also as their way out.
  537.  * If there is a message, and a way to display it, it will be displayed.
  538.  * Then free any resources, and exit!
  539.  */
  540.  
  541. static void bailout( char *message, int rc )
  542. {
  543.     if( message_console && message )
  544.     {
  545.         Write( message_console, message, strlen(message) );
  546.         Delay( 200 );
  547.     }
  548.  
  549.     cleanup();
  550.  
  551.     exit( rc );
  552. }
  553.  
  554.  
  555.  
  556. /* General purpose utility function to send messages to the ARexx
  557.  * resident process.  For simplicity's sake, we ask ARexx to not
  558.  * respond.  This does mean that a request could fail and we would
  559.  * never know.  Since there is _very_ little reason for anything
  560.  * we are doing here to fail, it seems a reasonable risk.  Else
  561.  * why would Bill have given us the RXFB_NONRET flag? :-)
  562.  */
  563.  
  564. static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
  565.     STRPTR arg3 )
  566. {
  567.     struct MsgPort *rmast;
  568.     struct RexxMsg *rexxmsg;
  569.  
  570.  
  571.     /* Allocate a packet to send to rexxmaster */
  572.     rexxmsg = CreateRexxMsg( NULL, NULL, NULL );
  573.     if( rexxmsg == NULL )
  574.     {
  575.         return( 1 );
  576.     }
  577.  
  578.     rexxmsg->rm_Action = cmd | RXFF_NONRET;
  579.  
  580.     rexxmsg->rm_Args[0] = arg0;
  581.     rexxmsg->rm_Args[1] = arg1;
  582.     rexxmsg->rm_Args[2] = arg2;
  583.     rexxmsg->rm_Args[3] = arg3;
  584.  
  585.     Forbid();
  586.     if(  rmast = FindPort( "REXX" )  )
  587.     {
  588.         PutMsg( rmast, (struct Message *)rexxmsg );
  589.     }
  590.     Permit();
  591.  
  592.     if( rmast == NULL )
  593.     {
  594.         /* we could not find the REXX port, this failed! */
  595.         DeleteRexxMsg( rexxmsg );
  596.         return( 2 );
  597.     }
  598.  
  599.     return( 0 );
  600. }
  601.  
  602.  
  603.  
  604. /* This will safely delete a message port used to recieve commands
  605.  * from ARexx.
  606.  * This is acomplished by setting a failure return code and replying the
  607.  * message if it is from ARexx.  If the message is not from ARexx, it
  608.  * is merely replied.
  609.  *
  610.  * The Forbid() Permit() bracketing is done to insure that the port
  611.  * is empty when we delete it.  It would be *very* rude to cause
  612.  * the ARexx resident process to hang waiting for us to reply a
  613.  * message that we never will...
  614.  */
  615.  
  616. static void rexx_delete_port( struct MsgPort *port )
  617. {
  618.     struct RexxMsg *rexxmsg;
  619.  
  620.  
  621.     Forbid();
  622.  
  623.     while( rexxmsg = (struct RexxMsg *)GetMsg( port ) )
  624.     {
  625.         if(  IsRexxMsg( rexxmsg )  )
  626.         {
  627.             /* Set failure code */
  628.             rexxmsg->rm_Result1 = RC_ERROR;
  629.             rexxmsg->rm_Result2 = ERR10_015;
  630.         }
  631.  
  632.         ReplyMsg( (struct Message *)rexxmsg );
  633.     }
  634.  
  635.     DeletePort( port );
  636.  
  637.     Permit();
  638. }
  639.  
  640.  
  641.  
  642. /* This can be called to handle the details of placing a result
  643.  * string into the rexx message packet as the result Argstring.
  644.  * This will deal with inability to allocate the Argstring.
  645.  * If the string pointer is NULL, a general failure code will
  646.  * be set.
  647.  */
  648.  
  649. void SetResultString( struct RexxMsg *rexxmsg, char *string )
  650. {
  651.     if( string )
  652.     {
  653.         rexxmsg->rm_Result1 = RC_OK;
  654.         rexxmsg->rm_Result2 =
  655.             (ULONG)CreateArgstring( string, strlen(string) );
  656.  
  657.         if( rexxmsg->rm_Result2 == NULL )
  658.         {
  659.             /* Unable to create the argstring */
  660.             rexxmsg->rm_Result1 = RC_ERROR;
  661.             rexxmsg->rm_Result2 = ERR10_012;
  662.         }
  663.     }
  664.     else
  665.     {
  666.         /* Result string is null, set general failure code */
  667.         rexxmsg->rm_Result1 = RC_ERROR;
  668.         rexxmsg->rm_Result2 = ERR10_012;
  669.     }
  670. }
  671.  
  672.